PUZZLE PLATFORMER TUTORIAL

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:

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 :

const c = document.getElementById("canvas").getContext("2d");

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:

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:

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.

Gravity

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):

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 wellThis 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:

If you're not sure about how to use event listeners go Here:https://www.w3schools.com/js/js_htmldom_eventlistener.aspOtherwise, 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:

function input() {
if (65 in keysDown) {
// checks that there is no block in the way
if (getTile((player.x - player.speed), player.y + 16) === "0") {
player.x -= player.speed;// moves to the left
}
}
if (68 in keysDown) {
//checks that there is no block in the way
if (getTile(((player.x + player.width) + player.speed), player.y + 16) === "0") {
player.x += player.speed;// moves to the right
}
}
//checks if the player is on the floor
if (87 in keysDown && player.yke === 0) {
player.gfldstr = -9.8;// changes gravity
}
//checks if the player is on the floor
if (83 in keysDown && player.yke === 0) {
player.gfldstr = 9.8;// changes gravity
}
// restarts the level
if (32 in keysDown && player.yke === 0) {
player.gfldstr = 9.8;
currentLevel = parseLevel(level);
}
}

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

I wish to thank you very much for making it to the end of my tutorial, I hope you enjoyed it.I also want to inform you that this is based off of Lucadukeys Basic Platformer Tutorial, but I did ask Lucadukey personally if I could use his bassis to create my own tutorial and we have agreed that any profit I might get from this (but probably not), he will get 50%. I would also like to say that I did code this myself and that I started develpoment before Lucadukey posted his tutorial. If you have any doubts I'm sure he would be happy to reply to your comments. Please Upvote it would mean a lot, and once again, Thankyou very Much.