Learn to Code via Tutorials on Repl.it!

← Back to all posts
How To Make A Puzzle Platformer In HTML5 And Javascript


What You Will Make:

By the end of this tutorial you should have a functioning puzzle platformer that allows the player to change gravity.
It should allow you to change gravity when you jump and have 4 different blocks that all do different things:

  • Plain Solid Block (does nothing)
  • One Way Gates (only allows you to pass one way - vertical only)
  • Sticky Block (no gravity changing)
  • Anti-grav Block (changes your gravity)

End Result: https://Puzzle-Platformer--bearbearmo.repl.co
The Code: https://repl.it/@bearbearmo/Puzzle-Platformer


This is likely not going to be the absolute best way to create a puzzle platformer, however I have done my best to make it simple but effective (which is very difficult).

In this tutorial you will not learn basic JavaScript concepts.

However if you wish to do so, I reccomend going to:https://www.w3schools.com/js/
It can show you almost everything, easily and conveniantly.

Also, it will be best if you follow along using a html + css + js repl as it automatically sets up everything for you, files, boilerplate stuff and makes it easy for you to code your dreams.

Beginning The Journey

To start of with creating a puzzle platformer we have to do the html; go to your index.html file and between the <body> and <script> tags add a canvas element, like so:

The id can be set to anything you want but for simplicity I will use "canvas". The width and height can be set to anything you like aslong as it is a multiple of 32 (512 is 16x32).And that is the only but most important html you will need to do.

The First Steps

The very first thing to do is to go to your script.js file on the Left Hand Side.

The first few things will be the easiest parts of this tutorial so they will be bundled into 1.

Defining Your Canvas

To define our canvas we will use const instead of var or let because we do not want to change the value.\
To define the canvas we do :

I have called the constant c so that it is short as I will be using it a lot. The getContext("2d") lets the program know to make the objects 2d (rather than 3d).

Creating Your Level

Creating your level is incredibley easy, all you have to do is create another constant const and call it level. However, this next part is important to follow or it will create real problems later on. You must make a string and fill it with (your canvas height divided by 32) rows of (your canvas width divided by 32) characters, creating (in my case) a 16 by 16 grid - fill it with "0"s but lines of "1" at the top and bottom and finaly add "bb^^PPvv" somewhere into the grid, like so:

Splitting Apart Your Nice New Level

To use your new level we need to create our first function, this function needs to:

  • split each row apart
  • split each character of each row apart
  • return the resulting 2d array

Luckily enough, javascript has two built in functions split() and map() we are going to utilise both of these to split our level. Like so:

Putting everything so far together we get this:

Running The Program

Now we have a program it would be usefull if we could run it; to do this we just add 2 new functions :

The first function is empty but will be filled up later on. The second function is activated when the window is loaded, it activates the entirety of the code. I'm also sure you noticed the let currentlevel; at the top of the extract, this new variable is needs to be introduced in the global domain, this is because we need to use it in many different functions. let allows us to change the value like a normal variable but dissallows the variable to be used before it is defined, stopping bugs that may arrise later on. The semi-colon allows us to define a new variable but without giving it a value until we are ready.

Getting To See Your Hard Work

Now we have our level split up and ready to utilate, we have to utilate it. Obviosly we want to draw it, so it is important to get familiar with c.fillStyle and c.fillRect(x, y, w, h) . c.fillStyle allows you to change the colour of the rectangles you fill. c.fillrect(x, y, w, h) draws a rectangle onto the canvas in the colour defined in c.fillStyle the brackets contain the x coordinate, ycoordinate, width, height. Now we know how to draw the level, we can create a function to do so. We are going to have to draw a block at a time and so we will need a for loop, however because our array is 2d we will need two for loops:

This allows us to access each blocks coordinates seperately, and so we can now easily, check the type of block("1","p","b","^","v"), select the colour for that block("black","pink","blue","grey"&"grey")and draw that block with it's coordinates(x(colx32),y(rowx32)) and size(w(32),h(32)). shown here:

note: It is worth mentoining now that the "^" blocks are one way gates upwards and the "v" blocks are one way gates downwards. This means they have to be half the height of a normal block (16) and the "v" needs to be on the bottom half of the block so has 16(half a block) added to its y coordinate.

To see the output of our draw function we just need to add draw(); to our main() function, and press run. The output should be a picture of your levels constant.

Acting God

Once we've got our level, we need to make a player. In this case a red square. This squares gonna need some associated values, for this we're going to create an object:

Whith the players coordinates and size we can easily draw it in the draw() function:

This draws in the square when we press run, however you cannot see it because it's coordinates are inside a block. To fix this we just need to add in a few more things. First of all in this example the player will be represented as "&", you need to write your symbol into the level constant(anywhere you like), for my example I'm placing it in the bottom left. Then you just need to write a simple if statement into the draw function, like so:

You should now have a red square appear wherever you placed your "&". The easy part of this tutorial is now complete. This is also a good time to talk about how we are going to make the player move. Well were going to be changing the coordinates of the player and then drawing it again in it's new coordinates, however to do this were going to have to use something that runs the entire code on a loop. The easiest way to do that is run the function main() on a loop by using requestAnimationFrame(main); basicly this will run main() every frame that the game is running. However, this creates a problem whenever the player is redrawn the old image is still there. To fix this, at the start of the draw() function we just need to put c.clearRect(0, 0, canvas.width, canvas.height); this wipes everything off the screen before we draw it back just after, this is a little inefficient as the whole level is redrawn every frame. To make this better we could just clear the players previous coordinates, but this creates a whole new set of problems that I'm not going to deal with in this tutorial. Just take my word for it, this way is better.


This is going to be the hardest part of the tutorial but keep whith it and you'll've made your own game.
To create gravity we have to create a new function calcGPE(obj) (it isn't important that you know the physics involved, however a deeper understanding of the physics used here could be helpfull for knowing what I'm doing.) In this function we need to find the vertical kinetic energy (YKE) , to do this we need to find the gravitational potential energy (GPE); the formula for GPE is GPE = GMH (Gravitational Feild Strength (obj.gfldstr/1000000) x Mass (obj.mass) x Height ((512 - obj.height) - (obj.y / 32)). This formula allows us to find the GPE of any object. This means our final function is:

The feild strength is divided by 1000000 because normal the height is in metres but in this measurement is in pixels so we need to account for that by dividing the feild strength by 1 million.

To make gravity act upon our player we need to create another function, gravity(obj) inside this new function we need to do 3 things take the kinetic energy from the y coordinate, take the gpe from the kinetic enrgy, find the gpe:

Now, if we add gravity(player); to the main function our player should fall out of the sky.\

Vertical Collisions

We want our player to collide with the blocks and stop, to do this we need to check the block bellow our player, check what kind of block it is and then stop the block if neccesary. However, we don't yet have an easy way of checking what a block is, so we create a new function, getTile(x, y):

Now we have that, we can easily check the block at whatever coordinates we want.\

To check the block under us is one we want solid, we just need a simple if statement:

To stop the player we need to set it's yke to 0 and round its y coordinate to the nearest 32:

The if statement just allows the player to leave the block again when we move up.

Now put this into the gravity function, make sure it's under everything allready in there.\
We can use this function again for the other blocks (apart from "v" because it allows us to move through it when coming from above.):

But of course being able to change gravity means that we need the blocks to be solid when we move upwards as well
This is easy to implement we just need to change the y coordinates that we check from y + 32 to just y. We also need to slow down the player before it meets the block to prevent it clipping in, as the previous rounnding of the coordinates does not work in this situation.
This means we need to add another 3 if statements:

And thats our vertical collisions finnished, the hardest part is done!

Getting Some exercise

Now we ahve a solid world, it's about time we moved through it. To do this we need to addEventListeners:

If you're not sure about how to use event listeners go Here:https://www.w3schools.com/js/js_htmldom_eventlistener.asp
Otherwise, you may have noticed keysdone has not been defined, so at the very top of the file under let currentlevel; put a new object let keysDown = {}; . The first event listener detects any keys currently pressed down and adds the keycode of that key. the second event listener detects any keys that have stopped being pressed down and removes the keycode of that key. This allows us to create a function that checks if the keys we want to be pressed down (w, a, s, d, spacebar) are pressed down, like so:

Now, The very last thing we need to do is add input(); to the main() function.\
Run the repl, and enjoy your new puzzle platformer. Remember you can create whatever levels you like and create as many levels as you like

Thank You Very Much

Thank you very much for making it to the end of my tutorial, I hope you enjoyed it.




How do you win?


@Julesdsf its a tutorial for how to make the mechanics of the game, the level i made is just to showcase the different mechanics. Its just a framework for you to add things to. If you decide to make the game then you can design your own levels and choose how you win


@bearbearmo Thanks!


anyone know why i got syntax error?


I think you were too unclear, i didn't know where to put the different functions and stuf. Please tell us where to put everything?


this concept is really cool, I'll try something similar out
(I especially like the blue block that just reflects you)


@Fhillis Thank you very much


This is so cool - great writeup. Got my vote :)