Week 4 packet
Student instructions, tasks, and checks. The answer key is not in this packet. Links stay as text. This page does not embed a clip or run a file.
# Week 04 — Solid movement
## VGC-L016 — Replace free motion with a physics body
**Objective:** Use CharacterBody2D velocity and move_and_slide correctly.
**Time:** 55 minutes
### Instruction
A CharacterBody2D lets Godot resolve motion against solid geometry. Follow C-BODY to make a reusable Player scene. Its velocity is measured in pixels per second; move_and_slide applies the physics step internally, so do not multiply this velocity by delta again. Use _physics_process for physics movement. The CollisionShape2D defines where the actor is solid, while _draw defines how it looks. Place the player above the world origin so it is visible before diagnosing collision problems.
### Worked example
A wall is a StaticBody2D with matching rectangle art and collider. A player standing next to it should be stopped by geometry, not by a special if statement checking the wall’s screen color.
Scaffold C-BODY — Reusable top-down player with collision
Setup: Create CharacterBody2D root Player at (80,180); add CollisionShape2D with CircleShape2D radius 14. Attach this script to Player and save Player.tscn. Use C-FREE-MOVE input actions. Root collision layer 1, mask 2. Create a separate StaticBody2D Wall on layer 2 mask 1 with RectangleShape2D collision and a Polygon2D rectangle as visible child. Instance both under an unscaled Node2D World. Do not put a body inside another physics body.
```gdscript
extends CharacterBody2D
@export var speed: float = 160.0
func _draw() -> void:
draw_circle(Vector2.ZERO, 14.0, Color.CORNFLOWER_BLUE)
draw_line(Vector2(-8, 0), Vector2(8, 0), Color.WHITE, 3.0)
func _physics_process(_delta: float) -> void:
velocity = Input.get_vector("move_left", "move_right", "move_up", "move_down") * speed
move_and_slide()
```
### Assignment
1. Create Player.tscn with a circle collider and C-BODY.
2. Run it in a blank World and compare its movement with the earlier actor.
### Acceptance checks
- Movement works in all four directions.
- The character has one active collision shape and no body-inside-body hierarchy.
**Submit:** Player scene/script and a node-tree screenshot.
**Question:** Why is delta absent from the velocity assignment in this recipe?
**Support:** Use a single rectangle wall and C-BODY. Enable visible collision shapes in the Debug menu before redesigning the level. Start with the first assigned task and re-run its acceptance test before adding the remaining feature.
**Optional extension:** Compare two collider sizes and explain how perceived fairness changes. Document one changed parameter, your prediction, and the observed effect; optional, not required for completion.
**Optional free reading:** [Godot step by step: nodes, scenes, GDScript, input, signals](https://docs.godotengine.org/en/stable/getting_started/step_by_step/index.html)
---
## VGC-L017 — Build walls that agree with their artwork
**Objective:** Create static obstacles and align visible and physics geometry.
**Time:** 55 minutes
### Instruction
A StaticBody2D is appropriate for an unmoving wall. Add a RectangleShape2D collider, then a visible Polygon2D rectangle with matching dimensions. Use size fields rather than nonuniformly scaling physics nodes. A wall that looks thin but has a wide invisible collider feels unfair. Put a wall at x320, y180 with a 32 by 180 rectangle. Begin with one wall so a failure has few possible causes. Use the Debug menu’s visible collision shapes while the project runs.
### Worked example
A wall is a StaticBody2D with matching rectangle art and collider. A player standing next to it should be stopped by geometry, not by a special if statement checking the wall’s screen color.
Scaffold C-BODY — Reusable top-down player with collision
Setup: Create CharacterBody2D root Player at (80,180); add CollisionShape2D with CircleShape2D radius 14. Attach this script to Player and save Player.tscn. Use C-FREE-MOVE input actions. Root collision layer 1, mask 2. Create a separate StaticBody2D Wall on layer 2 mask 1 with RectangleShape2D collision and a Polygon2D rectangle as visible child. Instance both under an unscaled Node2D World. Do not put a body inside another physics body.
```gdscript
extends CharacterBody2D
@export var speed: float = 160.0
func _draw() -> void:
draw_circle(Vector2.ZERO, 14.0, Color.CORNFLOWER_BLUE)
draw_line(Vector2(-8, 0), Vector2(8, 0), Color.WHITE, 3.0)
func _physics_process(_delta: float) -> void:
velocity = Input.get_vector("move_left", "move_right", "move_up", "move_down") * speed
move_and_slide()
```
### Assignment
1. Build the wall with matching 32 by 180 art and collider.
2. Approach each side and slide along its edge.
### Acceptance checks
- Player cannot pass through from either side.
- The visible boundary and collision outline agree.
**Submit:** World scene and collision-debug screenshot.
**Question:** Why can a visible wall still be passable?
**Support:** Use a single rectangle wall and C-BODY. Enable visible collision shapes in the Debug menu before redesigning the level. Start with the first assigned task and re-run its acceptance test before adding the remaining feature.
**Optional extension:** Compare two collider sizes and explain how perceived fairness changes. Document one changed parameter, your prediction, and the observed effect; optional, not required for completion.
**Optional free reading:** [Godot step by step: nodes, scenes, GDScript, input, signals](https://docs.godotengine.org/en/stable/getting_started/step_by_step/index.html)
---
## VGC-L018 — Read layers and masks as questions
**Objective:** Configure which objects exist on layers and which they detect.
**Time:** 55 minutes
### Instruction
A collision layer says what category an object belongs to; a mask says which categories it checks. Reserve layer 1 for Player and layer 2 for Walls. The bit values differ from the layer labels: layer 2 is bit value 2, while layer 3 is bit value 4. In the editor, use named layer boxes rather than guessing numbers. For this course Player scans Walls and Walls scan Player. A pickup will later detect Player without acting as a solid wall.
### Worked example
A wall is a StaticBody2D with matching rectangle art and collider. A player standing next to it should be stopped by geometry, not by a special if statement checking the wall’s screen color.
Scaffold C-BODY — Reusable top-down player with collision
Setup: Create CharacterBody2D root Player at (80,180); add CollisionShape2D with CircleShape2D radius 14. Attach this script to Player and save Player.tscn. Use C-FREE-MOVE input actions. Root collision layer 1, mask 2. Create a separate StaticBody2D Wall on layer 2 mask 1 with RectangleShape2D collision and a Polygon2D rectangle as visible child. Instance both under an unscaled Node2D World. Do not put a body inside another physics body.
```gdscript
extends CharacterBody2D
@export var speed: float = 160.0
func _draw() -> void:
draw_circle(Vector2.ZERO, 14.0, Color.CORNFLOWER_BLUE)
draw_line(Vector2(-8, 0), Vector2(8, 0), Color.WHITE, 3.0)
func _physics_process(_delta: float) -> void:
velocity = Input.get_vector("move_left", "move_right", "move_up", "move_down") * speed
move_and_slide()
```
### Assignment
1. Name physics layers Player, Walls, Pickups and Hazards.
2. Record the player/wall layer-and-mask matrix and intentionally break then restore one mask.
### Acceptance checks
- You can predict which pair collides from the matrix.
- Restoring the mask restores wall blocking.
**Submit:** Layer matrix and repaired project.
**Question:** Does placing a pickup on layer 3 mean its numeric bitmask is 3?
**Support:** Use a single rectangle wall and C-BODY. Enable visible collision shapes in the Debug menu before redesigning the level. Start with the first assigned task and re-run its acceptance test before adding the remaining feature.
**Optional extension:** Compare two collider sizes and explain how perceived fairness changes. Document one changed parameter, your prediction, and the observed effect; optional, not required for completion.
**Optional free reading:** [Godot step by step: nodes, scenes, GDScript, input, signals](https://docs.godotengine.org/en/stable/getting_started/step_by_step/index.html)
---
## VGC-L019 — Diagnose a collision systematically
**Objective:** Isolate a bug with reproducible steps instead of random edits.
**Time:** 55 minutes
### Instruction
A useful bug report states setup, action, expected result and observed result. For a wall-pass-through bug, check that Player is a CharacterBody2D, the wall is a StaticBody2D, both colliders are enabled, shapes overlap the intended pixels, and masks include the relevant layers. Change one cause at a time. A parse error can stop a script before physics runs at all, so read the first error in Debugger before editing geometry. Keep the last working backup untouched.
### Worked example
A wall is a StaticBody2D with matching rectangle art and collider. A player standing next to it should be stopped by geometry, not by a special if statement checking the wall’s screen color.
Scaffold C-BODY — Reusable top-down player with collision
Setup: Create CharacterBody2D root Player at (80,180); add CollisionShape2D with CircleShape2D radius 14. Attach this script to Player and save Player.tscn. Use C-FREE-MOVE input actions. Root collision layer 1, mask 2. Create a separate StaticBody2D Wall on layer 2 mask 1 with RectangleShape2D collision and a Polygon2D rectangle as visible child. Instance both under an unscaled Node2D World. Do not put a body inside another physics body.
```gdscript
extends CharacterBody2D
@export var speed: float = 160.0
func _draw() -> void:
draw_circle(Vector2.ZERO, 14.0, Color.CORNFLOWER_BLUE)
draw_line(Vector2(-8, 0), Vector2(8, 0), Color.WHITE, 3.0)
func _physics_process(_delta: float) -> void:
velocity = Input.get_vector("move_left", "move_right", "move_up", "move_down") * speed
move_and_slide()
```
### Assignment
1. Introduce one known fault: disable the wall collider.
2. Write a four-part report, verify the cause, restore the collider and repeat the same action.
### Acceptance checks
- The report reproduces the failure from a fresh run.
- The identical test passes after the single fix.
**Submit:** Bug report and fixed project checkpoint.
**Question:** Why should the same reproduction steps be used after the fix?
**Support:** Use a single rectangle wall and C-BODY. Enable visible collision shapes in the Debug menu before redesigning the level. Start with the first assigned task and re-run its acceptance test before adding the remaining feature.
**Optional extension:** Compare two collider sizes and explain how perceived fairness changes. Document one changed parameter, your prediction, and the observed effect; optional, not required for completion.
**Optional free reading:** [Godot step by step: nodes, scenes, GDScript, input, signals](https://docs.godotengine.org/en/stable/getting_started/step_by_step/index.html)
---
## VGC-L020 — Design an orchard route with fair clearance
**Objective:** Build a navigable level based on the collider footprint.
**Time:** 55 minutes
### Instruction
The player’s collider, not the artwork alone, determines which gaps are passable. A radius-fourteen circle needs more than twenty-eight pixels of gap for comfortable motion. Sketch a small orchard route with a start, three future pickup locations and two obstacles. Leave at least forty pixels between parallel obstacles. A route should be readable without forcing the player to scrape through invisible corners. Use rectangular obstacles for now; complex art and tilemaps would add unnecessary setup before the collection rule works.
### Worked example
A wall is a StaticBody2D with matching rectangle art and collider. A player standing next to it should be stopped by geometry, not by a special if statement checking the wall’s screen color.
Scaffold C-BODY — Reusable top-down player with collision
Setup: Create CharacterBody2D root Player at (80,180); add CollisionShape2D with CircleShape2D radius 14. Attach this script to Player and save Player.tscn. Use C-FREE-MOVE input actions. Root collision layer 1, mask 2. Create a separate StaticBody2D Wall on layer 2 mask 1 with RectangleShape2D collision and a Polygon2D rectangle as visible child. Instance both under an unscaled Node2D World. Do not put a body inside another physics body.
```gdscript
extends CharacterBody2D
@export var speed: float = 160.0
func _draw() -> void:
draw_circle(Vector2.ZERO, 14.0, Color.CORNFLOWER_BLUE)
draw_line(Vector2(-8, 0), Vector2(8, 0), Color.WHITE, 3.0)
func _physics_process(_delta: float) -> void:
velocity = Input.get_vector("move_left", "move_right", "move_up", "move_down") * speed
move_and_slide()
```
### Assignment
1. Sketch and build a 640 by 360 orchard with two obstacles and a reachable start.
2. Trace a route through three marked pickup positions.
### Acceptance checks
- All three markers are reachable without passing through walls.
- No required gap is narrower than 40 pixels.
**Submit:** Orchard layout photo/scan plus runnable geometry project.
**Question:** Why can a 20-pixel gap look open but block this player?
**Support:** Use a single rectangle wall and C-BODY. Enable visible collision shapes in the Debug menu before redesigning the level. Start with the first assigned task and re-run its acceptance test before adding the remaining feature.
**Optional extension:** Compare two collider sizes and explain how perceived fairness changes. Document one changed parameter, your prediction, and the observed effect; optional, not required for completion.
**Optional free reading:** [Godot step by step: nodes, scenes, GDScript, input, signals](https://docs.godotengine.org/en/stable/getting_started/step_by_step/index.html)
---
