Video Game Design and Coding · PLECK lesson
PLECK lesson 125 · suggested week 25, day 5
Integrate a fair guard challenge
Objective. Separate steering, damage sensing and round rules.
Godot Engine Standard desktop editor 4.7.2-stable, GDScript (Godot 4), Compatibility renderer. Headless Godot 4.7.2.stable.official.ed1daf0bf passed 106 assertions on the supplied scaffolds, including malformed JSON saves. Audio used the Dummy driver and a synthetic WAV, not a speaker. The visual editor, browser export, and signed-in submission were not tested. The desk still does not run a student's own upload.
About 55 minutes. The due date is chosen by a parent.
Patrol, detection, chase, return and readable fairness
Suggested pace: Recall and predict 5 min; Read instruction and scaffold 12 min; Build or design the assigned artifact 25 min; Run acceptance tests 8 min; Explain and checkpoint 5 min.
Materials: Godot Standard 4.7.2 desktop editor (GDScript, Compatibility renderer), Local course folder and prior checkpoint, No paid assets or public account required.
Comes after VGC-L124.
A guard’s motion script should not own the entire game. Add a separate Area2D contact sensor that notifies the manager when the player is touched. Reuse the recovery window or safe checkpoint policy from earlier games. Test whether the guard’s speed leaves a possible escape route. Show its detection cue without requiring sound. A guard that instantly catches the player at spawn is a layout problem even if its movement code is correct.
Worked example
A patrol guard follows two points. A separate manager handles damage, leaving steering reusable in another level with different round rules. Scaffold C-GUARD-AI — A readable patrol/chase/return state machine Setup: Create CharacterBody2D Guard with visible circle or polygon and matching collider. Layer 4 mask 2 for walls. Attach script and assign target to your Player instance in Inspector. Level is one open rectangle; this is steering, not navigation around walls. Damage remains a separate sensor/manager event. Draw detection radii on a design diagram before tuning values. ```gdscript extends CharacterBody2D enum Mode { PATROL, CHASE, RETURN } @export var target: Node2D @export var speed: float = 70.0 var mode: Mode = Mode.PATROL var home: Vector2 var patrol_target: Vector2 func _ready() -> void: home = global_position patrol_target = home + Vector2(80, 0) func _physics_process(delta: float) -> void: if not is_instance_valid(target): velocity = Vector2.ZERO return var distance: float = global_position.distance_to(target.global_position) if mode != Mode.CHASE and distance < 120.0: mode = Mode.CHASE elif mode == Mode.CHASE and distance > 180.0: mode = Mode.RETURN var destination: Vector2 if mode == Mode.CHASE: destination = target.global_position elif mode == Mode.RETURN: destination = home if global_position.distance_to(home) <= maxf(3.0, speed * delta): mode = Mode.PATROL else: destination = patrol_target if global_position.distance_to(patrol_target) <= maxf(3.0, speed * delta): patrol_target = home if patrol_target != home else home + Vector2(80, 0) var offset := destination - global_position velocity = offset.normalized() * minf(speed, offset.length() / maxf(delta, 0.001)) move_and_slide() ``` Scaffold C-STATES — Explicit game states and gated scoring Setup: Attach to Node root StateLab with child Label Status. This is a standalone demonstrator; call start_round, add_points, finish_round from buttons or Remote Inspector. In a real game the manager owns this state. Additional Player and spawner scripts must also honor the manager’s state, or be disabled when finishing. ```gdscript extends Node enum Phase { TITLE, PLAY, WIN, LOSE } var phase: Phase = Phase.TITLE var score: int = 0 func _ready() -> void: _show() func start_round() -> void: score = 0 phase = Phase.PLAY _show() func add_points(amount: int) -> void: if phase != Phase.PLAY: return score += maxi(amount, 0) _show() func finish_round(won: bool) -> void: if phase != Phase.PLAY: return phase = Phase.WIN if won else Phase.LOSE _show() func _show() -> void: $Status.text = "State: %s | Score: %d" % [Phase.keys()[phase], score] ```
A readable patrol/chase/return state machine
GDScript (Godot 4, not Scratch, Python, JavaScript or C#). Scaffold C-GUARD-AI. Copy starts from this text. The desk does not run it.
Scene and node setup
Create CharacterBody2D Guard with visible circle or polygon and matching collider. Layer 4 mask 2 for walls. Attach script and assign target to your Player instance in Inspector. Level is one open rectangle; this is steering, not navigation around walls. Damage remains a separate sensor/manager event. Draw detection radii on a design diagram before tuning values.
extends CharacterBody2D
enum Mode { PATROL, CHASE, RETURN }
@export var target: Node2D
@export var speed: float = 70.0
var mode: Mode = Mode.PATROL
var home: Vector2
var patrol_target: Vector2
func _ready() -> void:
home = global_position
patrol_target = home + Vector2(80, 0)
func _physics_process(delta: float) -> void:
if not is_instance_valid(target):
velocity = Vector2.ZERO
return
var distance: float = global_position.distance_to(target.global_position)
if mode != Mode.CHASE and distance < 120.0:
mode = Mode.CHASE
elif mode == Mode.CHASE and distance > 180.0:
mode = Mode.RETURN
var destination: Vector2
if mode == Mode.CHASE:
destination = target.global_position
elif mode == Mode.RETURN:
destination = home
if global_position.distance_to(home) <= maxf(3.0, speed * delta):
mode = Mode.PATROL
else:
destination = patrol_target
if global_position.distance_to(patrol_target) <= maxf(3.0, speed * delta):
patrol_target = home if patrol_target != home else home + Vector2(80, 0)
var offset := destination - global_position
velocity = offset.normalized() * minf(speed, offset.length() / maxf(delta, 0.001))
move_and_slide()
Checks to run in the editor
- Far player: guard patrols 80 pixels from home.
- Within 120 pixels: chase.
- Beyond 180 pixels: return, then patrol.
- Missing target stops safely rather than throwing an invalid-instance error.
Native Godot 4.7.2.stable.official.ed1daf0bf headless compile and representative node-tree/runtime tests passed; see native-qa-results.json. Visual UI, audible output, exports and website submission still need separate checks.
Explicit game states and gated scoring
GDScript (Godot 4, not Scratch, Python, JavaScript or C#). Scaffold C-STATES. Copy starts from this text. The desk does not run it.
Scene and node setup
Attach to Node root StateLab with child Label Status. This is a standalone demonstrator; call start_round, add_points, finish_round from buttons or Remote Inspector. In a real game the manager owns this state. Additional Player and spawner scripts must also honor the manager’s state, or be disabled when finishing.
extends Node
enum Phase { TITLE, PLAY, WIN, LOSE }
var phase: Phase = Phase.TITLE
var score: int = 0
func _ready() -> void:
_show()
func start_round() -> void:
score = 0
phase = Phase.PLAY
_show()
func add_points(amount: int) -> void:
if phase != Phase.PLAY:
return
score += maxi(amount, 0)
_show()
func finish_round(won: bool) -> void:
if phase != Phase.PLAY:
return
phase = Phase.WIN if won else Phase.LOSE
_show()
func _show() -> void:
$Status.text = "State: %s | Score: %d" % [Phase.keys()[phase], score]
Checks to run in the editor
- Calling add_points before start does not change score.
- After finish_round, extra score events do nothing.
Native Godot 4.7.2.stable.official.ed1daf0bf headless compile and representative node-tree/runtime tests passed; see native-qa-results.json. Visual UI, audible output, exports and website submission still need separate checks.
Integrate a fair guard challenge — evidence task
- 1. Integrate one guard into an open Garden Patrol room with a collectible goal.
- 2. Test spawn safety, escape, contact recovery and completion.
Deliverable. Guard challenge checkpoint and four-test log.
Acceptance checks
- VGC-L125-T1. Player can leave the start without immediate unavoidable damage.
- VGC-L125-T2. Contact and completion respect the manager’s phase.
Understanding question. Why keep guard steering separate from the manager’s lives or win state?
Include a downloadable project ZIP with project.godot, .tscn, .gd and original asset files when code changes. A private, teacher-accessible download link to that ZIP is equivalent. Screenshots or a playthrough do not replace editable source.
If this is still shaky. Use an open room and C-PATROL before C-GUARD-AI. Do not expect direct steering to navigate a maze. Start with the first assigned task and re-run its acceptance test before adding the remaining feature.
Optional extra. Add a visible state label or icon and compare how it changes player understanding. Document one changed parameter, your prediction, and the observed effect; optional, not required for completion.
- Your first 2D game
Free public tutorial; no account; external asset download is optional, not used by this course.
· Opening this link does not submit the lesson.
Name ____________________ Date ____________________