Week 3 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 03 — Scenes, coordinates, input
## VGC-L011 — Draw a visible actor in a coordinate system
**Objective:** Place an original shape using local and scene coordinates.
**Time:** 55 minutes
### Instruction
In Godot 2D, positive x goes right and positive y goes down. A Node2D’s position is relative to its parent; draw commands use coordinates relative to the node. C-DRAW places a circle at its own local origin. Moving the root moves the entire drawing. Save Actor.tscn so this scene can be reused. A drawing is only visual: it does not automatically create a physics collision shape. Keep the parent unscaled while learning so pixel distances are predictable.
### Worked example
A circle drawn at Vector2.ZERO belongs to its Node2D origin. If its parent is at (100,80) and its local position is (20,10), its world origin is (120,90) when neither parent is rotated or scaled.
Scaffold C-DRAW — Draw an original geometric actor
Setup: Create Node2D root Actor. Attach actor.gd. Save Actor.tscn. A draw command uses coordinates relative to Actor. Set its Position to (200,150) in the Inspector. Change the blue color or white marker to make original art. No imported artwork is needed.
```gdscript
extends Node2D
func _draw() -> void:
draw_circle(Vector2.ZERO, 14.0, Color(0.15, 0.5, 0.9))
draw_line(Vector2(-8, 0), Vector2(8, 0), Color.WHITE, 3.0)
```
### Assignment
1. Build C-DRAW at (200,150), then place it at (400,100).
2. Sketch the axes and label local origin versus scene position.
### Acceptance checks
- The marker and circle move together.
- Changing the root position does not require changing draw_circle coordinates.
**Submit:** Actor scene/script and annotated coordinate sketch.
**Question:** Does draw_circle create a solid physics obstacle?
**Support:** Use a 640 by 360 viewport, one unscaled Node2D and the C-DRAW recipe before adding movement. Start with the first assigned task and re-run its acceptance test before adding the remaining feature.
**Optional extension:** Add a second independently colored actor without changing the first actor’s script. Document one changed parameter, your prediction, and the observed effect; optional, not required for completion.
**Optional free reading:** [Godot 4.7.2 stable archive and platform downloads](https://godotengine.org/download/archive/4.7.2-stable/), [Godot step by step: nodes, scenes, GDScript, input, signals](https://docs.godotengine.org/en/stable/getting_started/step_by_step/index.html)
---
## VGC-L012 — Instance a scene twice
**Objective:** Distinguish a shared scene definition from individual instances.
**Time:** 55 minutes
### Instruction
An instance is a use of a saved scene. Create a World Node2D scene, then drag Actor.tscn into it twice. The two actors share the saved shape recipe but have separate positions. Renaming an instance or changing its transform does not require duplicating its script. Editing the source Actor scene updates both when they use the same source. Reuse prevents slightly different copies of the same behavior from drifting apart during later fixes.
### Worked example
A circle drawn at Vector2.ZERO belongs to its Node2D origin. If its parent is at (100,80) and its local position is (20,10), its world origin is (120,90) when neither parent is rotated or scaled.
Scaffold C-DRAW — Draw an original geometric actor
Setup: Create Node2D root Actor. Attach actor.gd. Save Actor.tscn. A draw command uses coordinates relative to Actor. Set its Position to (200,150) in the Inspector. Change the blue color or white marker to make original art. No imported artwork is needed.
```gdscript
extends Node2D
func _draw() -> void:
draw_circle(Vector2.ZERO, 14.0, Color(0.15, 0.5, 0.9))
draw_line(Vector2(-8, 0), Vector2(8, 0), Color.WHITE, 3.0)
```
### Assignment
1. Create two actor instances named Courier and Marker at distinct positions.
2. Change the source drawing’s radius once and observe both.
### Acceptance checks
- Two independent positions persist when reopening World.
- A source drawing change appears in both instances.
**Submit:** World and Actor project checkpoint plus before/after screenshot.
**Question:** Which change should be made on the source scene if every courier needs it?
**Support:** Use a 640 by 360 viewport, one unscaled Node2D and the C-DRAW recipe before adding movement. Start with the first assigned task and re-run its acceptance test before adding the remaining feature.
**Optional extension:** Add a second independently colored actor without changing the first actor’s script. Document one changed parameter, your prediction, and the observed effect; optional, not required for completion.
**Optional free reading:** [Godot 4.7.2 stable archive and platform downloads](https://godotengine.org/download/archive/4.7.2-stable/), [Godot step by step: nodes, scenes, GDScript, input, signals](https://docs.godotengine.org/en/stable/getting_started/step_by_step/index.html)
---
## VGC-L013 — Map actions rather than hardcoding keys
**Objective:** Create named input actions with alternate keyboard bindings.
**Time:** 55 minutes
### Instruction
An input action describes intent, such as move_left, rather than one physical key. In Project Settings > Input Map, create four movement actions and bind both WASD and arrow keys as shown in C-FREE-MOVE. The script asks Godot for the action, so two input devices can express the same intention. Check exact spelling and case: move_Left and move_left are different names. Use physical key events for movement and keep a visible controls note. Do not replace built-in ui_accept navigation actions.
### Worked example
A circle drawn at Vector2.ZERO belongs to its Node2D origin. If its parent is at (100,80) and its local position is (20,10), its world origin is (120,90) when neither parent is rotated or scaled.
Scaffold C-FREE-MOVE — Frame-independent movement without collisions
Setup: Use Node2D root Actor, attach this script in place of C-DRAW. Project Settings > Input Map: add move_left, move_right, move_up, move_down. Bind A/Left, D/Right, W/Up, S/Down respectively using physical key events. Project Settings > Display > Window: viewport width 640 height 360. Local Actor has no transformed parent. This version moves but cannot collide with walls.
```gdscript
extends Node2D
@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 _process(delta: float) -> void:
var direction := Input.get_vector("move_left", "move_right", "move_up", "move_down")
position += direction * speed * delta
position.x = clampf(position.x, 14.0, 626.0)
position.y = clampf(position.y, 14.0, 346.0)
```
### Assignment
1. Configure all four actions with two bindings each.
2. Print a short message on a just-pressed movement action and test both bindings.
### Acceptance checks
- A and Left trigger the same intention.
- Holding a key does not spam a just-pressed message every frame.
**Submit:** Input-map project files and a binding table.
**Question:** Why is just_pressed useful for a menu selection but not continuous movement?
**Support:** Use a 640 by 360 viewport, one unscaled Node2D and the C-DRAW recipe before adding movement. Start with the first assigned task and re-run its acceptance test before adding the remaining feature.
**Optional extension:** Add a second independently colored actor without changing the first actor’s script. Document one changed parameter, your prediction, and the observed effect; optional, not required for completion.
**Optional free reading:** [Godot 4.7.2 stable archive and platform downloads](https://godotengine.org/download/archive/4.7.2-stable/), [Godot step by step: nodes, scenes, GDScript, input, signals](https://docs.godotengine.org/en/stable/getting_started/step_by_step/index.html)
---
## VGC-L014 — Move by speed times elapsed time
**Objective:** Explain delta and prevent faster diagonal travel.
**Time:** 55 minutes
### Instruction
A game draws many frames each second, but frame duration varies. Moving a fixed pixel count each frame makes a faster computer move farther each second. C-FREE-MOVE multiplies speed in pixels per second by delta in seconds. Input.get_vector combines four actions and limits length to one, preventing diagonal movement from becoming faster. Read the code as units: pixels/second times seconds equals pixels. This free-moving actor is not a physics body and cannot stop against a wall.
### Worked example
A circle drawn at Vector2.ZERO belongs to its Node2D origin. If its parent is at (100,80) and its local position is (20,10), its world origin is (120,90) when neither parent is rotated or scaled.
Scaffold C-FREE-MOVE — Frame-independent movement without collisions
Setup: Use Node2D root Actor, attach this script in place of C-DRAW. Project Settings > Input Map: add move_left, move_right, move_up, move_down. Bind A/Left, D/Right, W/Up, S/Down respectively using physical key events. Project Settings > Display > Window: viewport width 640 height 360. Local Actor has no transformed parent. This version moves but cannot collide with walls.
```gdscript
extends Node2D
@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 _process(delta: float) -> void:
var direction := Input.get_vector("move_left", "move_right", "move_up", "move_down")
position += direction * speed * delta
position.x = clampf(position.x, 14.0, 626.0)
position.y = clampf(position.y, 14.0, 346.0)
```
### Assignment
1. Replace Actor script with C-FREE-MOVE and run as a single actor.
2. Measure rightward travel for roughly one second and compare diagonal distance.
### Acceptance checks
- At speed 160, motion is roughly 160 pixels per second away from clamps.
- Diagonal vector length is at most one.
**Submit:** Moving Actor project and measurement note.
**Question:** Why would position += direction * speed without delta be frame-dependent?
**Support:** Use a 640 by 360 viewport, one unscaled Node2D and the C-DRAW recipe before adding movement. Start with the first assigned task and re-run its acceptance test before adding the remaining feature.
**Optional extension:** Add a second independently colored actor without changing the first actor’s script. Document one changed parameter, your prediction, and the observed effect; optional, not required for completion.
**Optional free reading:** [Godot 4.7.2 stable archive and platform downloads](https://godotengine.org/download/archive/4.7.2-stable/), [Godot step by step: nodes, scenes, GDScript, input, signals](https://docs.godotengine.org/en/stable/getting_started/step_by_step/index.html)
---
## VGC-L015 — Keep movement inside a usable playfield
**Objective:** Test boundaries and explain a first interactive prototype.
**Time:** 55 minutes
### Instruction
Boundary handling is part of the rules, not a cosmetic afterthought. The actor’s radius is fourteen pixels, so its center must stay at least fourteen pixels from the viewport edge. Clamping the center to zero still clips half the circle. Test all four edges and diagonal corners. Save a named checkpoint and restore it into a new practice folder to verify that project.godot, scene and script are present. Explain one code line in your own words rather than reading the entire script aloud.
### Worked example
A circle drawn at Vector2.ZERO belongs to its Node2D origin. If its parent is at (100,80) and its local position is (20,10), its world origin is (120,90) when neither parent is rotated or scaled.
Scaffold C-FREE-MOVE — Frame-independent movement without collisions
Setup: Use Node2D root Actor, attach this script in place of C-DRAW. Project Settings > Input Map: add move_left, move_right, move_up, move_down. Bind A/Left, D/Right, W/Up, S/Down respectively using physical key events. Project Settings > Display > Window: viewport width 640 height 360. Local Actor has no transformed parent. This version moves but cannot collide with walls.
```gdscript
extends Node2D
@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 _process(delta: float) -> void:
var direction := Input.get_vector("move_left", "move_right", "move_up", "move_down")
position += direction * speed * delta
position.x = clampf(position.x, 14.0, 626.0)
position.y = clampf(position.y, 14.0, 346.0)
```
### Assignment
1. Test and document four edges and two corners.
2. ZIP and restore the project into a new local folder, then run it.
### Acceptance checks
- No part of the actor crosses the 640 by 360 viewport boundary.
- Restored project runs with the same input bindings.
**Submit:** First interactive prototype ZIP, boundary checklist and two-sentence explanation.
**Question:** For radius 14 and width 640, what is the largest safe center x?
**Support:** Use a 640 by 360 viewport, one unscaled Node2D and the C-DRAW recipe before adding movement. Start with the first assigned task and re-run its acceptance test before adding the remaining feature.
**Optional extension:** Add a second independently colored actor without changing the first actor’s script. Document one changed parameter, your prediction, and the observed effect; optional, not required for completion.
**Optional free reading:** [Godot 4.7.2 stable archive and platform downloads](https://godotengine.org/download/archive/4.7.2-stable/), [Godot step by step: nodes, scenes, GDScript, input, signals](https://docs.godotengine.org/en/stable/getting_started/step_by_step/index.html)
---
