Smooth Criminal
So our four-cornered amigo’s movement is very jerky, and we need to make it moonwalk-smooth. On top of that, we can only move like a rook around our game arena, and we want diagonal movement. As noted previously, this is because the event listener is only passing the most recently detected key press to our playerMove function.
To make the movement smooth, we need to change our approach slightly.
First a reminder – the below object is what the event listener passes to the playerMove function:
keydown { target: <canvas#canvas>, key: "w", charCode: 0, keyCode: 87 }
This is for the “w” key. Note that there’s a “key” property, but also a “keyCode.” In JavaScript, every key has a special code number associated with it. For our movement keys, these codes are:
w = 87
a = 65
s = 83
d = 68
Now hold that thought for a second. Hopefully you’re at least somewhat familiar with arrays. An array is a bit like a filing cabinet with a load of drawers. These “drawers” can hold variables, objects, or even other arrays. Each drawer in the array is given an index number, which you use to tell your program to put things in the drawers, or retreive things from them. Let’s define an array called keys, like this:
var keys = [];
Now let’s update our event listeners as follows:
canvas.addEventListener("keydown", function (e) { keys[e.keyCode] = true; }); canvas.addEventListener("keyup", function (e) { keys[e.keyCode] = false; });
If you refer to an array and put a number in square brackets after it, you are referring to the “drawer” with that index number. For example, “console.log(keys[87]);” will display on the console whatever is in position 87 in the array called “keys”.
Our event listeners are now going into the keys array, and going to position e.keyCode and putting “true” in that drawer. We also have a new event listener, “keyup,” which detects when the player releases a key. When that happens, we put “false” in that drawer.
For example, if you press “w”, the code works like this:
- When you press “w”, the event listener detects that, and passes an object to a function. The function labels the object “e”.
- The “e” object has a property called keyCode, to which JavaScript automatically assigns the unique code for the key that was pressed.
- The “w” key’s keyCode is 87. Therefore e.keyCode = 87.
- We go to position 87 in the array and set it to “true.” Note that “keys[e.keyCode] = true;” is the same as “keys[87] = true”.
- When the key is released, the keyup event listener detects that, and changes keys[87] to “false”.
Now we can detect multiple key presses! We just need to check if the values at positions 65, 68, 83 and 87 in the keys array are set to true. If they are, we know the player has pressed these keys.
We can update playerMove to do just that:
function playerMove(e){ if (keys[87]) { Player1.y -= 1; } if (keys[83] ) { Player1.y += 1; } if (keys[65] ) { Player1.x -= 1; } if (keys[68] ) { Player1.x += 1; } return false; }
Saying “if (keys[87])” is equivalent to saying “if (keys[87] === true)”. So now playerMove checks the keys array, and checks whether the variables in positions 87, 83, 65 and 68 are set to “true”. These correspond to the w, s, a and d keys, of course. If any of these are true, playerMove updates the player’s x or y coordinates accordingly. If not, the program does nothing.
We just need to do one more thing. Previously we called playerMove whenever we detected a key press. Now, we’re updating the values in the keys[] array whenever we detect a keypress. So there’s no longer a line of code telling JavaScript to run the playerMove function. No problem, just add the following into mainDraw:
playerMove();
In every iteration of the game loop, our program will run playerMove, and check whether any keys are currently being pressed.
He’s a killer…
From rook to queen! Now our champion can move vertically, horizontally, and diagonally. We can change directions smoothly, too.
But, as the old saying goes, the devil makes work for idle right-angles. He’s going to get pretty bored just walking around that empty green field. Let’s give him something to do.