For a long time I’ve wanted to make stuff move in the browser. The problem I’ve had for the longest time is trying to get my head around synchronous code and asynchronous code. How can I make the player move when I press a key, but mix the event based nature of the browser with the synchronous style of coding I use when solving problems or puzzles.
To create simple code that can be managed, we’ll be separating displaying the game with the game data. The game data will reside in an object that will be drawn through an
First let’s set up the html so we can see what we’re doing. We will be using svg elements because they’re easy to set up and fast enough for our needs. We’ll use a rectangle for our player and a line to set the floor boundary. To set up the svg screen with a line and rectangle add the following code to your html.
The screen will now include the ground drawn at the bottom of the screen. Svg elements can be modified using css the same way other elements can be styled. However svg elements have different CSS properties that are specific to svg shapes.
Before jumping into the logic, let’s take a look from afar at the process we’ll be using. We want a function to run ~30 times a second to change data in the game and also draw the screen. We want events like pressing a key and releasing a key to be monitored, and therefore influence the logic that runs. We’ll want to store data in some kind of data store (an object we’ll call
worldData) and then base our game loop on that data. The end of our game loop will also have an
update function that creates the frame.
So let’s set up the data and update function!
Our game data requires x and y coordinates for the player. We’ll make this an object so we can easily add data later on. I want the player to start on the ground, centred on the screen, but feel free to write in your own numbers.
The player rectangle hasn’t moved yet though. To move it we need to create an
render function. Call it whatever makes most sense to you, however I’ll be using
update. This function uses the worldData to draw a frame. This shouldn’t be too complicated as all we’ll be doing is linking the
worldData.player.x to the rectangles
x property, and the same with the
Now the rectangle will jump to the position you’ve specified in your
Let’s create a game loop that executes 30 times a second. This loop will have all our logic, and end with the
update() function call that updates the svg to reflect the new data.
Your player now lifts off the ground! Let’s unpack why this is happening.
setInterval takes a function and calls it over and over again with an interval in milliseconds. In this case we’re calling the function every 30 milliseconds. That’s about 33 frames per second. Every time this function runs, it changes the
worldData.player.y by subtracting
0.5. At the end of the function we are updating the frame by calling
update we don’t see the liftoff!
Let’s add interaction. We need a way to know which key is down. This is the hardest part, but once you understand it you can add as many keys as you want to your game and it’s easy. We need to keep track of which keys are down. We’ll add
keysDown as a property to the
keysDown will contain a list of all keys the person playing your game is holding down. With this information we’ll be able to see which keys are down in the game-loop (the function within the
setInterval above) and move the player accordingly.
First let’s add
keysDown as a property in the
worldData object. It should now look like so:
We use the document’s event listeners to keep track of keys being pressed.
In your console you can see the events firing off as you press buttons on your keyboard. Let’s create a function that adds the arrow keys pressed to the list in your
worldData object. We’ll call this function
fireKeyAction and it’ll handle
We also want to update our key press and key up events.
Let’s walk through it quickly.
When you press a key, it finds the name of the key you pressed using
event.key. This is a string representation of the key, e.g.
ArrowLeft. This is passed into
fireKeyAction which takes two arguments. A key string, and a boolean, representing if it’s a
Assuming we’re handling a
keydown event. In
fireKeyAction we pass the argument
true. We then reach the
switch statement. This is a shorthand method of checking if
=== to the various
case statements. In this example we are only going to do anything if the
key is equal to any of the arrow keys.
If the user has pressed or released an arrow key we add or remove it from the
keysDown array. If
true, we add the arrow key, but only if it’s not already in the array. This is important because the keydown event fires continuously while a key is pressed down. We only want to add the key once. If
false, we find the key with
indexOf and use
splice to cut it from the
Go back to the mainloop (the function inside setInterval), and add a
console.log for the
All that is left is adding logic to the game loop. Let’s make the character walk left and right. In your setInterval anonymous function, update it so it matches the following:
Notice I’ve used a function
isKeyDown in the
if statements. Let’s quickly add that function:
This is just a shortcut for checking if the key is in the array.
Add other features by adding a key, more logic in the setInterval game loop or by adding more svg elements.
The way I’ve organised the code is heavily influenced by the book How to Design Programs, Second Edition which is freely available on the web!
This lesson uses mutation of the
worldData object which is not good practice, especially when things get complicated. If you want to add complexity and grow your game, I’d recommend taking a look at Redux. Check out this introduction to Redux by making another game! Redux gives you a safe way to change the state of your game and keep track of the changes. As motivation, with Redux you could trivially add time travelling to your game.
Got any questions, comments or found errors? Tweet me over on my twitters! :)
Hacker Noon is how hackers start their afternoons. We’re a part of the @AMIfamily. We are now accepting submissions and happy to discuss advertising &sponsorship opportunities.
To learn more, read our about page, like/message us on Facebook, or simply, tweet/DM @HackerNoon.
If you enjoyed this story, we recommend reading our latest tech stories and trending tech stories. Until next time, don’t take the realities of the world for granted!