Welcome back. Your explorer now responds to W, A, S, and D, and the dungeon exit changes when the Boolean variable hasDungeonKey becomes true. At the moment, though, the player can keep moving until they disappear through a wall.
This lesson adds the rule that makes the room feel solid: after movement, the game checks whether the player has crossed a boundary and, if necessary, puts them back at the nearest safe position. You will use four if statements—one each for the left, right, top, and bottom walls. Plan for about 35–40 minutes.
A wall needs a rule, not just a drawing
The stone rectangles in your sketch look like walls, but drawing them does not automatically stop anything. Your player’s position is still just two changing numbers:
playerX
playerY
When the player holds D, this code keeps increasing playerX:
playerX = playerX + playerSpeed;
Eventually, playerX becomes too large and the player travels through the right wall. To prevent that, the game needs to ask, every frame:
“Has the player moved beyond the safe right edge?”
If the answer is yes, the game corrects playerX.
A boundary check has the familiar conditional shape:
if (someCondition) {
// Correct the player position.
}
For example:
if (playerX > 557) {
playerX = 557;
}
The condition playerX > 557 is either true or false.
- When it is
false, the player is still in the room, so nothing happens. - When it is
true, the player has tried to cross the right boundary, so the game sets their position back to557.
This is a different use of if from the locked-exit if/else in the previous lesson. An exit must be in exactly one visual state, locked or unlocked. But a player might reach a corner, crossing both the left/right boundary and the top/bottom boundary in the same frame. Therefore, we want four separate if statements, not one if/else if chain.
Where are the safe edges?
p5.js places coordinate (0, 0) at the top-left corner of the canvas:
xincreases as you move right.yincreases as you move down.widthis the canvas width:600in your project.heightis the canvas height:400in your project.
Your walls are 28 pixels thick. The player is a circle with diameter 30, so its radius is 15.
That radius matters because playerX and playerY describe the center of the circle, not its outer edge. If you stopped the player at x = 28, half of their body would be inside the left wall.
The player’s center must stay at least:
pixels from the left or top canvas edge.
On the right, the center must stay at most:
On the bottom, it must stay at most:
So the safe area for the player’s center is:
| Boundary | Safe player-center value |
|---|---|
| Left | playerX = 43 minimum |
| Right | playerX = 557 maximum |
| Top | playerY = 43 minimum |
| Bottom | playerY = 357 maximum |
You could write those four numbers directly. But it is better to keep the meanings visible in the code: wallThickness and playerRadius.
Watch a boundary check being built
The following short segment from “How to create collisions, walls, and barriers in the P5.js programming language” by Jason Erdreich shows the basic pattern: test a position against 0, width, or height, then adjust the position to force the object back within the canvas.
How to create collisions, walls, and barriers in the P5.js programming language
Watch this for the core idea behind four separate edge checks. The example uses a moving rectangle and pushes it inward after it crosses a canvas edge.
Watch four border checks. Focus on how a value below 0 means the object passed the left or top edge, while a value beyond width or height means it passed the right or bottom edge. Our dungeon version will also account for wall thickness and the circle player's radius.
The video moves the rectangle back by its movement amount. For your game, assigning the player to the exact safe edge is slightly more reliable: even if you later increase playerSpeed, the player will not get partly stuck in or beyond a wall.
Add named measurements
At the top of your sketch, near your existing variable declarations, add these two lines:
let wallThickness = 28;
let playerRadius = 15;
Your declarations might now look like this:
let playerX = 300;
let playerY = 200;
let playerSpeed = 4;
let playerHealth = 3;
let hasDungeonKey = false;
let wallThickness = 28;
let playerRadius = 15;
These are ordinary number variables. wallThickness matches the 28 used to draw the walls, and playerRadius is half of the player circle’s diameter of 30.
Later, changing a value such as wallThickness will be an easy way to alter the dungeon room. For now, their main job is to make the boundary calculations understandable.
Add the four boundary checks
Inside draw(), find the keyboard movement checks. Add the following block after all the movement checks and before background(...).
// Keep the center of the player inside the inner edges of the walls.
if (playerX < wallThickness + playerRadius) {
playerX = wallThickness + playerRadius;
}
if (playerX > width - wallThickness - playerRadius) {
playerX = width - wallThickness - playerRadius;
}
if (playerY < wallThickness + playerRadius) {
playerY = wallThickness + playerRadius;
}
if (playerY > height - wallThickness - playerRadius) {
playerY = height - wallThickness - playerRadius;
}
The beginning of your draw() function should have this overall structure:
function draw() {
// Read keyboard input and update the player position.
if (keyIsDown('KeyW')) {
playerY = playerY - playerSpeed;
}
if (keyIsDown('KeyA')) {
playerX = playerX - playerSpeed;
}
if (keyIsDown('KeyS')) {
playerY = playerY + playerSpeed;
}
if (keyIsDown('KeyD')) {
playerX = playerX + playerSpeed;
}
// Temporary test control from the previous lesson.
if (keyIsDown('KeyK')) {
hasDungeonKey = true;
}
// Keep the center of the player inside the inner edges of the walls.
if (playerX < wallThickness + playerRadius) {
playerX = wallThickness + playerRadius;
}
if (playerX > width - wallThickness - playerRadius) {
playerX = width - wallThickness - playerRadius;
}
if (playerY < wallThickness + playerRadius) {
playerY = wallThickness + playerRadius;
}
if (playerY > height - wallThickness - playerRadius) {
playerY = height - wallThickness - playerRadius;
}
// Redraw the dungeon floor.
background(18, 21, 31);
// The wall and player drawing code continues here.
}
The order is important. In each repeated frame, the sketch:
- Reads held movement keys and changes the position.
- Checks whether that new position is outside the allowed room.
- Corrects the position if it is outside.
- Draws the dungeon using the corrected position.
By checking after movement but before drawing, the player never visibly travels through the wall.
Read one check carefully
Consider the left-wall rule:
if (playerX < wallThickness + playerRadius) {
playerX = wallThickness + playerRadius;
}
With your current values, JavaScript evaluates the expression:
wallThickness + playerRadius
as:
28 + 15
which is 43.
So this is equivalent to:
if (playerX < 43) {
playerX = 43;
}
If holding A makes playerX become 39, the condition is true. The game immediately changes it back to 43. The player’s left edge is then at:
That is exactly where the inside edge of the left wall begins.
The right-wall version uses subtraction:
if (playerX > width - wallThickness - playerRadius) {
playerX = width - wallThickness - playerRadius;
}
Here, width is p5.js’s built-in canvas-width value. Since your canvas is 600 pixels wide, the safe right-center position is:
Using width and height rather than repeatedly typing 600 and 400 keeps the check connected to the actual canvas size.
Test the room like a game developer
Press Play, click the canvas if necessary, and test one edge at a time:
- Hold A until the player reaches the left wall.
- Hold D until the player reaches the right wall.
- Hold W until the player reaches the top wall.
- Hold S until the player reaches the bottom wall.
- Hold two movement keys together toward a corner, such as W and A.
The player should stop with their edge touching the inside of each wall rather than with their center at the wall. At a corner, both relevant checks can run: one corrects playerX, and the other corrects playerY.
You should also still be able to move along a wall. For example, while held against the top wall, A and D should still work. Only the coordinate that would escape the room is corrected.
A few common problems have simple causes:
| What you see | Likely cause | Fix |
|---|---|---|
| Player still moves through walls | Boundary code is above the movement checks or outside draw() | Place all four checks after keyboard movement, inside draw() |
| Player overlaps a wall | The check uses 0, width, or height without accounting for wall thickness and radius | Use wallThickness + playerRadius and the subtraction expressions |
| Error saying a name is not defined | A variable name is misspelled or not declared at the top | Check capitalization in wallThickness and playerRadius |
| Player stops too far from a wall | playerRadius does not match the circle | With circle(playerX, playerY, 30), use playerRadius = 15 |
Be especially careful not to replace a comparison with assignment. This is correct:
if (playerX > width - wallThickness - playerRadius) {
This is not:
if (playerX = width - wallThickness - playerRadius) {
The first asks a true-or-false question using >. The second changes playerX, which is not what the condition is meant to do.
Key takeaways
Your dungeon now has walls that affect gameplay, not just decoration.
- A boundary check uses an
ifstatement to detect an unsafe position. - p5.js provides
widthandheightfor the current canvas dimensions. - The player’s coordinates describe the center of the circle, so the checks must include the player radius.
- Because the room has four independent edges, use four separate
ifstatements. - Place boundary checks after movement updates and before drawing the frame.
- Assigning the player to the exact safe coordinate keeps them reliably inside the room.
Next, you will practice spotting and correcting small mistakes in a short p5.js program—an essential skill once a game has several movement, drawing, and rule blocks working together.
Can't find a good explanation? Sign up and we'll make it for you
Sign up