Manipulating the DOM with events by making a platformer!

Written by spyr1014 | Published 2017/01/06
Tech Story Tags: javascript | web-development | freecodecamp | svg | manipulating-the-dom

TLDRvia the TL;DR App

We’ll be making this fun square!

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.

Today we’ll create a simple character that can move and jump around a space. We’ll achieve this with ~70 lines of JavaScript without the help of any libraries. Follow along using CodePen or your own editor.

Particles can also be added!

I’m assuming you have a basic understanding of JavaScript syntax, including some basic ES6 features. If not read my refresher on ES6 first!

Click here for the finished code.

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 update function.

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.

This will draw an svg screen. Width and height needs to be specified, but we’ll do this with JavaScript. The line won’t be visible yet as it’s outside the dimensions of the svg screen.

Let’s set up the data for the screen and player in JavaScript.

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 update or 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 y property.

Now the rectangle will jump to the position you’ve specified in your worldData object.

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.

It’s lonely out in space

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. Without 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 worldData object. 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 keydown and keyup events.

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 keydown or keyup event.

Assuming we’re handling a keydown event. In fireKeyAction we pass the argument isDown as true. We then reach the switch statement. This is a shorthand method of checking if key is === 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 isDown is 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 isDown is false, we find the key with indexOf and use splice to cut it from the keysDown array.

Go back to the mainloop (the function inside setInterval), and add a console.log for the worldData.keysDown.

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.

It’s ALIVE!

Add other features by adding a key, more logic in the setInterval game loop or by adding more svg elements.

A colourful trail!

I shoot!

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!


Published by HackerNoon on 2017/01/06