Tag Archives: onkeydown

Creating a Running Game in VueJS – Part 1 – Moving

If, like me, you’re over the age of 35, you may have owned a Spectrum, Amstrad, or Commodore 64. One of the games, especially on the Spectrum, that was guaranteed to ruin your keyboard, and make your family think you were having some kind of fit, was Daley Thomson’s Decathlon.

In this post, I introduced the basics of writing a game in VueJS. In this series of posts, I’m going to try to recreate that game, at least in spirit. I’m afraid I won’t have the amazing graphics, but hopefully we can create something vaguely similar.

I’ll be putting the various parts in GitHub here. I made a similar series of posts using React; you can find them here.

In this first section, we’ll create a player (it’ll just be a box on the screen for now), and a timer. To get the code, look here.

Let’s start by seeing the HTML:

<div id="app">
    <div v-bind:style="location"></div>
    <p>{{ secondsRemaining }}</p>
</div>

We’re simply binding the style of the div to one computed property, and secondsRemaining is another. Let’s see what the computed section looks like next:

computed: {                    
    location: function() {
        return 'width:10px; height:10px; left:' + this.playerX + 'px; top:' + this.playerY + 'px; border:1px solid #000; position: absolute;';
    },
    secondsRemaining: function() {
        const diff = (this.startTime - this.timeNow) / 1000;
        return Math.round(diff);
    }
},

Remember that this section will cause a screen refresh when the variables it uses change; it does not know that the function will return a different value otherwise; which is why I’m not getting the current time inside the secondsRemaining function.

The location will force an update when the playerX or playerY properties change. Let’s see the data:

data: {                    
     playerX: 100,
     playerY: 100,
     speed: 0,
     toggleSpeed: 1,                    
     startTime: 0,
     timeNow: 0
},

There’s just two more set-up points – the first is the mounted() method:

mounted() {
    this.init();
}

This is another lifecycle event; it’s called late on in the start-up process, after everything is created. We’ll come back to Init() shortly.

Next we have created(): this is early on in the lifecycle, and here we’re just going to create an event listener:

created() {
    window.addEventListener('keydown', this.onKeyDown);
},

That’s pretty much all the set-up. Everything else is in the methods() section. Let’s start with the init() method that we saw earlier:

init() {
    setInterval(this.update, 10);
    this.startTime = new Date();
    this.startTime.setSeconds(this.startTime.getSeconds() + 20);
},

All we’re doing here is initialising the timer, and creating an update loop. Let’s see the update() method next:

update() {
    this.playerX += this.speed;
    if (this.speed > 0) {
        this.speed -= 0.01;
    } else {
        this.speed = 0;
    }
    this.timeNow = new Date().getTime();
}

This is the update method, but it’s more akin to a draw method: it’s limited to updating the variables that force a screen update. It also slows the runner down naturally (so if the player does nothing, the character will stop).

There’s just one more thing we have yet to see, and that’s the method that handles the keypress; which, in fact, is two methods:

onKeyDown(e) {                        
    switch (e.which) {
        case 37: // Left
            this.playerRun(1); 
            break;
        case 39: // Right
            this.playerRun(2); 
            break;
        default:
            break;
    }
},
                    
playerRun(toggle) {                        
    if (this.toggleSpeed !== toggle) {                           
        this.speed += 0.12;
        this.toggleSpeed = toggle;
    }
},                  

One of the defining features of the original game was that you ran by pressing the left key, and then the right in quick succession; we’ve emulated this by simply setting a flag, and comparing them.

That’s it, the first part complete:

I know you’re probably wondering how I managed to great such amazing graphics!

The code works (after a fashion), but it’s messy. In Part 2, we’ll refactor this code into components.

Creating a Car Game in React – Part 1 – Drawing and Moving

Since I started looking at React, I’ve wondered whether it would be possible to create a multi-user game. The game would look a little like a Spectrum game that I used to play called: Trans-Am. I’m guessing most people reading this are not going to be old enough to remember this. Essentially, it marks the peak of car game development, and everything has been down hill ever since.

If you have no idea what I’m talking about then there’s a demo of the game here.

I’m not going to try and emulate this exactly, I thought I’d use it as a basis to make a multi-player car game.

The GitHub repository for this post can be found here.

Create a React Application

We’ll start by creating a new React Application (see here for details):

Now we have the application, we’ll need some game assets. If you want to use the same assets as me then feel free to pull my repository. However, at this stage, all you’ll need is a square box and a green screen.

Game Layout

The next stage is to design the game layout; because this is React, we’ll start with App.js. We’ll delegate all of our game logic to a component called Game:

import React from 'react';
import './App.css';
import Game from './Components/Game';
function App() {
	return (
		<div className="App">
			<Game />
		</div>
		);
}
export default App;

If you want to see, comprehensively what Game.Jsx looks like, then have a look at the latest version on GitHub. However, some of the highlights are the render method:

render() { 
	return <div onKeyDown={this.onKeyDown} tabIndex="0">
		<Background backgroundImage={backgroundImg}
		windowWidth={this.state.windowWidth} windowHeight={this.state.windowHeight} /> 
	<Car carImage={carImg} centreX={this.state.playerX} 
		centreY={this.state.playerY} width={this.playerWidth}
		height={this.playerHeight} /> 
	</div>
}

This will probably change as to game progresses, but at the minute, it just renders to two constituent components. We’re also responding to KeyDown here, so let’s have a look at onKeyDown:

onKeyDown(e) {
	switch (e.which) {
		case 37: // Left
			this.playerMove(this.state.playerX - this.SPEED, this.state.playerY); 
			break;
		case 38: // Up
			this.playerMove(this.state.playerX, this.state.playerY - this.SPEED);
			break;
		case 39: // Right
			this.playerMove(this.state.playerX + this.SPEED, this.state.playerY); 
			break;
		case 40: // Down
			this.playerMove(this.state.playerX, this.state.playerY + this.SPEED);
			break;
		default:
			break;
	}
} 

playerMove(x, y) {
	this.setState({
		playerX: x,
		playerY: y
	}); 
}

We’re storing the players position in state; as I detailed here, this enables us to update the state and have React update the screen as it detects a change in the Virtual DOM.

Game Components

In an effort to stay as close as possible to React’s preferred architecture, the components of the game (the background and the cars for now) will be, well, components. Background is easy:

import React from 'react';
function Background(props) {
	const bgStyle = { 
		width: `calc(${props.windowWidth}px)`, 
		height: `calc(${props.windowHeight}px)`, 
		top: 0,
		left: 0,
		position: 'absolute' 
	};
	return (
		<img src={props.backgroundImage} style={bgStyle} />
	);
}
export default Background;

We’re basically just displaying an image here. One thing that’s worth noting is that the windowWidth and windowHeight are properties, not state. They do exist as state in the Game component and, when they change, are updated there, and so updated here. The React guys call this Lifting State.

The car component is exactly the same idea:

import React from 'react';
function Car(props) {
	const left = Math.round(props.centreX - (props.width / 2));
	const top = Math.round(props.centreY - (props.height / 2));
	const carStyle = { 
		width: `calc(${props.width}px)`, 
		height: `calc(${props.height}px)`, 
		top: `calc(${top}px)`,
		left: `calc(${left}px)`, 
		position: 'absolute',
		zIndex: 1 
	};
	return (
		<img src={props.carImage} style={carStyle} />
	);
}
export default Car;

There are a number of advantages to this idea of maintaining the state in a higher component; for example, this way, you can share a single state between components; however, the biggest advantage for us is that, while the components are, effectively, intelligent sprites, you can easily create an “EnemyCar” version of the Car component.

It’s worth bearing in mind that, because the position of the car doesn’t exist in this component as state, we wouldn’t be able to change it here, even if we wanted to. The strategy to get around this is to have an update function passed in as a property (effectively a function pointer that you can call from within the child component).

In the next post, I’m going to update the movement so it’s a little more car-like, and introduce some obstacles.

References

https://reactjs.org/docs/components-and-props.html

https://stackoverflow.com/questions/43503964/onkeydown-event-not-working-on-divs-in-react

https://stackoverflow.com/questions/37440408/how-to-detect-esc-key-press-in-react-and-how-to-handle-it/46123962

https://reactjs.org/docs/lifting-state-up.html

https://stackoverflow.com/questions/36862334/get-viewport-window-height-in-reactjs

Basic Game Using HTML5 and Javascript

This article discusses how to go about creating a basic game loop in HTML5 / JS and to implement control over a sprite.

Introduction

A few years ago, when Microsoft released the idea of WinJS, I wrote a game in HTML5/JS (or WinJS – they are not exactly the same).

I recently decided to see if I could write a web game, using just HTML5 and Javascript. This article covers the initial POC and results in a small red square navigating around the screen:

Game Loop

Looking at established game frameworks, they all basically give you the same things:
– A game loop, consisting of an update and draw phase
– Some helper methods for manipulating graphics, or rendering them to the screen

My attempt will be different, I’ll just provide a game loop; here it is:

(function MainGame() {    

    setInterval(function() {
        Update();
        Draw();
    }, 20);
})();

The loop executes every 20ms, meaning that there are 50 frames per second.

HTML

Basically, what the HTML gives us here is a canvas; so the page is very simple:

<head>    
    <script type="text/javascript" src="./gamelogic.js" ></script>
</head>
<body onresize="onResizeGameWindow()">    
    <canvas id="mainCanvas" style="width: 100%; height: 100%"
        onkeydown="onKeyDown()" tabindex="0">
    </canvas>
</body>

There are two events handled here, because there are two things that the player can do: they can interact with the game (i.e. press a key), and they can resize the browser window. We need to react to both.

Draw

Let’s have a look at the draw function next. All this is, is a way of displaying all the objects on the screen in a controlled fashion:

    function Draw() {
        var canvas = document.getElementById("mainCanvas");
        var ctx = canvas.getContext("2d");
        ctx.clearRect(0, 0, windowWidth, windowHeight);

        ctx.fillStyle = "#FF0000";
        ctx.fillRect(x, y, iconWidth, iconHeight);
    }

As you can see, there are effectively two parts to this function: firstly, the canvas is cleared, and then the items (in this case, a single item) are drawn to the screen. The important variables here are x and y, because that dictates where the square is drawn; the rest could be hard-coded values.

Update

    function Update() {        
        if (initialised == 0) {
            initialise();
        }

        // Bounce
        if (x >= (windowWidth - iconWidth) 
            && directionX > 0)
            directionX = -1;
        else if (x <= 0 && directionX < 0)
            directionX = 1;

        if (y >= (windowHeight - iconHeight)
            && directionY > 0)
            directionY = -1;
        else if (y <= 0 && directionY < 0)
            directionY = 1;

        // Move
        x += directionX * speed;
        y += directionY * speed;
    }

There are three parts to the Update. The first is to perform any initialisation: in my case, I focus on the canvas and call the resize event here. This potentially could be done on an event, but you would still have to check inside this loop if it had been done. The second is to stop the player leaving the screen; and finally, we adjust the player position.

Events

As you saw earlier, there are two events that are handled; the first is the user resizing the screen:

function onResizeGameWindow() {
    var canvas = document.getElementById("mainCanvas");
    
    windowWidth = canvas.width;
    windowHeight = canvas.height;
}

This basically ensures that the game adjusts to the browser dimensions. This might also be where you would determine if the window was made so small that the game could no longer be played.

The second event was the keydown event. This effectively provides the control for the player:

function onKeyDown(e) {
    if (!e) e = window.event;     

    if (e.keyCode == 39) {
        directionX++;
    }
    else if (e.keyCode == 37) {
        directionX--;
    }

    if (e.keyCode == 38) {        
        directionY--;
    }
    else if (e.keyCode == 40) {        
        directionY++;
    }
}

The top line is because the parameter comes through as null.

Conclusion

If you run this game, you’ll see that you can move the square around the screen, increase and decrease its speed, and stop. Not exactly the next Call Of Duty, I’ll grant you, but the foundation of a game, certainly.