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 only works if the player can jump high enough to clear it. Change these numbers. 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. To add a platform, you add one line to that list. 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. That is the bottom of the world. A platform's y is how high it sits above the floor. The platform at y: 240 is 240 pixels up. A higher platform has a bigger number.
Do two rectangles overlap?
Most 2D games use a function like this one. These four lines do most of the work. The function asks the same question twice. It asks once about the left-right direction and once about 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. That test has two parts.
player.velocityY <= 0means the player is falling, not rising.- Subtract
velocityYfrom the player's feet. That tells you where the feet were on the previous frame. If the feet were above the platform then, the player is 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. At first the list holds only the ground. Draw the platforms indraw()with aforEachloop. Use 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 the function right on its own. Only then 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. Then 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. You can also jump up through it and land on top.Design a level
Edit the
platformslist. Build a jump that takes practice to land. This is the reward for turning the level into data.
Try these changes
Make these changes in the files beside this guide. Each one only uses what this lesson has already covered. Tick each one when it works.
Check yourself
Three quick questions on this lesson. Get them all right to finish the lesson and earn a pack.
Loading your answers
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 rectangles on a grid. Read each of the four lines out loud against the drawing. - Insist on step 2. Students should test the function in the console, away from the game. That 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. They can describe it and then fix it. If you explain the falling test first, you waste that.
- Give real time to step 5. Some students do not enjoy the code. Level design is where those students start enjoying the project.