Lesson 3 of 4
Platforms and Collisions
Replace the single floor with a list of platforms. Then write the overlap test that every 2D game uses.
What you will learn
- A list of objects as level data
- Rectangle overlap
- One-way platforms
- forEach
Before you start
Gravity and Jumping. The ground check becomes a real collision function.
What this stage does
There are now four platforms above the ground. Jump onto them. Try jumping up through one from below. You pass through it and land on top. Then walk into the side of one. You pass through that too.
Can you still reach the top?
A level is only as good as the jump that has to clear it. Change these and see which platforms go out of reach.
Turn this down until the higher platforms are out of reach.
The level is just a list
The ground is no longer a single number. It is one item in a list. Adding a platform is now adding one line. You write no new code for it.
const platforms = [
{ x: 0, y: 0, width: 600, height: 50 }, // the ground
{ x: 200, y: 140, width: 100, height: 10 },
{ x: 400, y: 190, width: 100, height: 10 },
{ x: 600, y: 240, width: 100, height: 10 },
{ x: 800, y: 0, width: 300, height: 50 },
];The ground sits at y: 0, the bottom of the world. A platform's y is how high off the floor it is, so the one at y: 240 is 240 pixels up. Higher platform, bigger number.
Do two rectangles overlap?
This four-line function does the heavy lifting in most 2D games. It asks the same question about the left-right direction and the up-down direction.
function rectsCollide(a, b) {
return (
a.x < b.x + b.width && // is A's left inside B's right edge?
a.x + a.width > b.x && // is A's right inside B's left edge?
a.y < b.y + b.height && // is A's bottom inside B's top edge?
a.y + a.height > b.y // is A's top inside B's bottom edge?
);
}Landing on top, and only on top
Overlapping is not enough. If every overlap counted as landing, the player would jump to the top of a platform they walked into from the side. So the code adds a second test with two parts.
player.velocityY <= 0means the player is falling, not rising.- Subtracting
velocityYfrom the player's feet asks where the feet were on the previous frame. If they were above the platform then, they are landing on it now.
function handleCollisions() {
platforms.forEach((platform) => {
if (!rectsCollide(player, platform)) return;
const platformTop = platform.y + platform.height;
if (player.velocityY <= 0 &&
player.y - player.velocityY >= platformTop) {
player.y = platformTop;
player.velocityY = 0;
player.isJumping = false;
}
});
}The result is a one-way platform. You can jump up through it and land on top. Most platform games work this way.
Build it step by step
Step 3 has a bug in it on purpose. That bug is the reason for step 4.
Turn the floor into data
Replace
groundTopwith aplatformslist that holds only the ground. Draw the platforms indraw()with aforEachloop, using the samedrawRect. The game should look and play exactly as it did before.Write rectsCollide and test it alone
Write the function. Then call it from the console with two rectangles you can check on paper. Get it right on its own before you use it in the game.
rectsCollide({x:0, y:0, width:10, height:10}, {x:5, y:5, width:10, height:10}) // true rectsCollide({x:0, y:0, width:10, height:10}, {x:50, y:0, width:10, height:10}) // falseLand on any overlap
Write
handleCollisions()with only therectsCollidecheck inside. Stop the player on any overlap. Call it after gravity. Add the higher platforms and play. Walk into the side of one. You jump to its roof. That is the bug.Add the falling test
Add the
velocityY <= 0part and the previous-frame check. Walk into a platform's side again. Now you pass through it, and you can jump up through it and land on top.Design a level
Edit the
platformslist. Build a jump that you have to practise. This is the reward for turning the level into data.
Try these changes
Make these in the files beside this guide. None of them need anything the lesson has not covered.
- Add a platform that the player cannot pass through from any direction.
- Make one platform move, by changing its `x` inside `update()`.
- Make a platform disappear after the player stands on it.
- Give each platform a `colour` value and use it in `draw()`.
Teacher's versionHow to run this lesson, what to check, and any answers. Students do not need this.
How to teach it
- Teach
rectsCollideon paper first. Draw two boxes on a grid and read each of the four lines out loud against the picture. - Insist on step 2. Testing the function in the console, away from the game, is the habit worth building. A wrong collision test inside a running game is very hard to debug.
- Do not skip the broken version in step 3. Popping to the roof of a platform is a bug the student can see, describe, and then fix. Explaining the falling test first wastes it.
- Give real time to step 5. Level design is where students who are not enjoying the code start enjoying the project.