Avoiding Un-win-able Games
Now it’s time to actually put together a stage, with gaps for the player to jump over and everything.
The most important element here is making sure that the gaps are small enough that the player can always jump over them. It’s neither fun nor fair to hit the player with an impossibly large obstacle.
So that means we have to figure out how far the player can jump, which depends on two things: 1) How long the player is in the air 2) How fast the player is moving forward while in the air.
For example, if the player’s jump leaves him in the air for two seconds and the player is moving 100 pixels per second the player can safely jump a 200 pixel gap.
Now we already know that our player can move 5 pixels to the left or right per frame. But to figure out how long they can stay in the air we’re going to need to do a little math.
You might remember from physics that a moving object’s position can be described by the equation: current position = starting position + velocity * time + ½ acceleration * time^2.
Now this equation doesn’t quite match our frame-based game world physics, but it will still give us a close estimate. So let’s plug in some numbers and find out how long it takes for an object to reach the ground (position 0) if it starts at position 0 with a velocity of -15 pixels per second and an acceleration of 1 pixel per second per second.
0 = 0 – 15t + ½t^2.
15t = ½ t^2
15=1/2t
t=30
According to this our cycle’s jump takes 30 frames, or about a second and a half, to complete. And from testing the code so far that feels about right.
So 30 frames of airtime while moving 5 pixels to the right per frame means our cycle can move 150 pixels in one jump.
To test this I’m going to shrink the current “ground” testObject to only fill a third of the screen and then insert a second testObject2 150 pixels further to the right. I will then add code for testing collisions with testObject2 so I can practice jumping between them.
I’m also going to add code to detect when the motorcycle has fallen off the bottom of the screen. Eventually we’ll want this code to trigger some sort of game over message but for now we’ll just have it drop the cycle back into starting position. It would be a real pain to have to reload the game testing page every time we fell off the screen.
This code goes near the top of your script, before any function declarations:
var testObject = new Object();
testObject.x = 0;
testObject.y = 350;
testObject.width = 200;
testObject.height = 20;
var testObject2 = new Object();
testObject2.x = 350;
testObject2.y = 350;
testObject2.width = 200;
testObject2.height = 20;
And the drawScreen function needs to be changed like this to draw two rectangles instead of just one:
//Draw red squares the player can jump on
context.fillStyle = '#FF0000';
context.fillRect(testObject.x, testObject.y, testObject.width, testObject.height);
context.fillRect(testObject2.x, testObject2.y, testObject2.width, testObject2.height);
And the collision detection section of the updateGame function needs to be changed to this:
if(intersectRect(testObject, getFeetHitbox(player.x, player.y))){
feetCollision = true;
player.yVel=0;
player.y=testObject.y-48;
player.onGround=true;
}
if(intersectRect(testObject2, getFeetHitbox(player.x, player.y))){
feetCollision = true;
player.yVel=0;
player.y=testObject2.y-48;
player.onGround=true;
}
if(intersectRect(testObject, getDeathHitbox(player.x, player.y))){
deathCollision = true;
}
if(intersectRect(testObject, getGrazeHitbox(player.x, player.y))){
grazeCollision = true;
}
//Reset the player to default location when they fall off the screen
if(player.y > 400){
player.x = 100;
player.y = 100;
}
Run the game now and you can jump between the two red platforms and confirm that 150 pixel jump is just about right for jumping distance.
Next Time: Lot’s More Platforms
With this little bit of prep work out of the way we can finally write some code to automatically generate and position hundreds of platforms. This game will finally start feeling like a game!