Make an obstacle physically block the route
Build collision bodies from rectangles and use the same rectangles to draw the boundaries.
Godot 4.7.2 stable · standard edition · GDScript · 25 minutes estimated practiceContinue your working project from the previous lesson. Each download is the completed version of this lesson, for recovery and comparison. Start lesson one with checkpoint 01.
Describe the room geometry once
Continue from lesson two, or use checkpoint 02 as your starting point. Open game.gd and add the following WALLS constant after START. Each Rect2 contains x, y, width and height in the room’s coordinates.
The first four rectangles form the room’s boundary. The last rectangle is a divider: it begins at y=140 and stops at y=420, leaving a route below it. The courier’s radius is 12 pixels, so a usable gap needs room for its whole collision shape.
const WALLS: Array[Rect2] = [
Rect2(40, 140, 880, 16), Rect2(40, 564, 880, 16),
Rect2(40, 140, 16, 440), Rect2(904, 140, 16, 440),
Rect2(450, 140, 36, 280)
]Give the rectangles real collision
Add this _add_walls function at the end of game.gd, aligned with the other func declarations. It creates one fixed physics body and one matching rectangle collision shape for each entry.
Then put a single _add_walls() call at the beginning of _ready(), before its status.text assignment. _ready runs when this scene enters the tree, so the wall bodies are created once for the run.
- Check that _ready() calls _add_walls() once. Do not put the call in _process or _physics_process; those run repeatedly.
- Save and run. The bodies should block movement even before the next drawing edit makes them easy to see.
func _add_walls() -> void:
for rectangle in WALLS:
var wall := StaticBody2D.new()
wall.position = rectangle.get_center()
var collision := CollisionShape2D.new()
var shape := RectangleShape2D.new()
shape.size = rectangle.size
collision.shape = shape
wall.add_child(collision)
add_child(wall)Draw the same geometry
At the end of the existing _draw() function, after its final draw_string call and before the next func declaration, add the loop below. Preserve one tab of indentation for the loop and two for its draw_rect call.
Using WALLS for both drawing and collision keeps the visible obstacle matched to its physical boundary. A drawn rectangle by itself does not stop a CharacterBody2D.
- Run the game. Push into the divider from the left, then find the open route beneath it.
- Try each outside edge and a diagonal approach to a corner. Check that the courier stays within the room.
- Compare your game.gd with checkpoint 03 if the shapes appear but do not block movement, or block movement but are invisible.
for rectangle in WALLS:
draw_rect(rectangle, Color("6e826d"))Check your work.
- The courier stops against the divider.
- The courier can travel through the gap below the divider.
- The four outside boundaries prevent leaving the room.
- Visible walls and their collision edges agree.
If something went wrong.
- A drawing has no physics body until _add_walls creates one.
- Each collision rectangle uses rectangle.get_center() as the body position and rectangle.size as its shape size.
- The new drawing loop belongs inside _draw; _add_walls is a separate function at the outer indentation level.
Ask about one small step.
I am on the Godot 4.7.2 One Small Delivery walls lesson. WALLS stores Rect2 entries used to draw rectangles and create StaticBody2D/CollisionShape2D pairs. Help diagnose my observed collision result. Ask for the relevant code and exact symptom, then propose one check that distinguishes drawing, shape size, position or function-call problems.