Video Game Design and Coding

Week 14 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 14 — Level state and checkpoints

## VGC-L066 — Activate a midpoint checkpoint

**Objective:** Store a safe global coordinate once the player reaches it.

**Time:** 55 minutes

### Instruction
A checkpoint changes where a future retry begins. Put an Area2D on the broad middle platform; its handler calls set_checkpoint with a safe Marker2D global_position. The marker should be above the platform, not at the trigger’s edge. Change the checkpoint’s visible symbol when activated and show a short text message. Re-entering it may repeat feedback but must not move the safe position into a wall. For now checkpoints last only for the current session.

### Worked example
A checkpoint trigger and safe spawn marker serve different roles. The trigger notices arrival, while the marker specifies a collision-free return location above a platform.

Scaffold C-CHECKPOINT — A safe checkpoint respawn
Setup: Add this pattern to a separate Node2D level root with child Player using C-PLATFORM. Call set_checkpoint with a safe global position when a player reaches a checkpoint Area2D; call respawn when entering a fall zone. This code does not connect Area2D automatically; select the area body_entered signal in editor and call these methods from its handler after checking the player group. Respawn is deferred because a physics callback may be active.
```gdscript
extends Node2D
@onready var player: CharacterBody2D = $Player
var checkpoint: Vector2
func _ready() -> void:
    checkpoint = player.global_position
func set_checkpoint(safe_position: Vector2) -> void:
    checkpoint = safe_position
func respawn() -> void:
    _apply_respawn.call_deferred()
func _apply_respawn() -> void:
    player.global_position = checkpoint
    player.velocity = Vector2.ZERO
```

### Assignment
1. Add a midpoint Area2D and safe Marker2D.
2. Activate, advance, fall and verify the new respawn location.

### Acceptance checks
- Before activation, falls return to start.
- After activation, falls return to the midpoint safely.

**Submit:** Checkpoint project and before/after fall tests.

**Question:** Why store the Marker2D global_position rather than its local position?

**Support:** Use one checkpoint on a broad platform and keep the camera fixed until respawn is reliable. Start with the first assigned task and re-run its acceptance test before adding the remaining feature.

**Optional extension:** Compare start-only retries with a midpoint checkpoint using the same route. Document one changed parameter, your prediction, and the observed effect; optional, not required for completion.

**Optional free reading:** [Your first 2D game](https://docs.godotengine.org/en/stable/getting_started/first_2d_game/index.html)

---

## VGC-L067 — Keep the next action visible

**Objective:** Frame the level with Camera2D and clear environmental cues.

**Time:** 55 minutes

### Instruction
For a level wider than one screen, add Camera2D as a Player child and enable it. Set limits to the level bounds and test a simple horizontal route before adding smoothing. A camera that reveals the next landing only after a jump creates an unfair blind decision. Use a visible arrow or platform edge cue where the camera cannot show everything. Camera motion changes the view, not the physics coordinates or collider sizes. The HUD remains in CanvasLayer so it stays readable.

### Worked example
A checkpoint trigger and safe spawn marker serve different roles. The trigger notices arrival, while the marker specifies a collision-free return location above a platform.

Scaffold C-PLATFORM — A gravity-and-jump platform player
Setup: CharacterBody2D root Player, child CollisionShape2D RectangleShape2D size (24,32), no scale changes. Layer 1 mask 2. StaticBody2D floor layer 2 mask 1 with rectangular collider. Add Input Map move_left, move_right and jump bound to Space. Place player above floor, not intersecting it. Coordinates use positive y downward. Attach script to Player.
```gdscript
extends CharacterBody2D
@export var speed: float = 160.0
@export var gravity: float = 900.0
@export var jump_speed: float = 340.0
func _draw() -> void:
    draw_rect(Rect2(-12, -16, 24, 32), Color.SKY_BLUE)
    draw_line(Vector2(-8, -4), Vector2(8, -4), Color.BLACK, 2.0)
func _physics_process(delta: float) -> void:
    velocity.x = Input.get_axis("move_left", "move_right") * speed
    if not is_on_floor():
        velocity.y += gravity * delta
    if Input.is_action_just_pressed("jump") and is_on_floor():
        velocity.y = -jump_speed
    move_and_slide()
```

### Assignment
1. Extend the route horizontally and add a limited Camera2D.
2. Inspect takeoff views for every jump and fix blind required landings.

### Acceptance checks
- Camera does not reveal empty world outside intended limits.
- HUD stays fixed while the world scrolls.

**Submit:** Scrolling level and three takeoff screenshots.

**Question:** Does Camera2D movement move the actual platforms?

**Support:** Use one checkpoint on a broad platform and keep the camera fixed until respawn is reliable. Start with the first assigned task and re-run its acceptance test before adding the remaining feature.

**Optional extension:** Compare start-only retries with a midpoint checkpoint using the same route. Document one changed parameter, your prediction, and the observed effect; optional, not required for completion.

**Optional free reading:** [Your first 2D game](https://docs.godotengine.org/en/stable/getting_started/first_2d_game/index.html)

---

## VGC-L068 — Make collision feedback trustworthy

**Objective:** Separate solid platforms, sensors and decorative objects.

**Time:** 55 minutes

### Instruction
Players infer rules from repeated visual patterns. A solid platform should look consistently solid, while a background decoration should not unexpectedly block movement. Label your node categories: StaticBody2D for solid floor, Area2D for checkpoint or goal, Node2D visuals for decoration. Match collider boundaries to artwork and remove tiny invisible lips at joins. Test walking slowly along platform seams and jumping against undersides. A collision issue that looks like poor jumping may actually be misaligned geometry.

### Worked example
A checkpoint trigger and safe spawn marker serve different roles. The trigger notices arrival, while the marker specifies a collision-free return location above a platform.

Scaffold C-PLATFORM — A gravity-and-jump platform player
Setup: CharacterBody2D root Player, child CollisionShape2D RectangleShape2D size (24,32), no scale changes. Layer 1 mask 2. StaticBody2D floor layer 2 mask 1 with rectangular collider. Add Input Map move_left, move_right and jump bound to Space. Place player above floor, not intersecting it. Coordinates use positive y downward. Attach script to Player.
```gdscript
extends CharacterBody2D
@export var speed: float = 160.0
@export var gravity: float = 900.0
@export var jump_speed: float = 340.0
func _draw() -> void:
    draw_rect(Rect2(-12, -16, 24, 32), Color.SKY_BLUE)
    draw_line(Vector2(-8, -4), Vector2(8, -4), Color.BLACK, 2.0)
func _physics_process(delta: float) -> void:
    velocity.x = Input.get_axis("move_left", "move_right") * speed
    if not is_on_floor():
        velocity.y += gravity * delta
    if Input.is_action_just_pressed("jump") and is_on_floor():
        velocity.y = -jump_speed
    move_and_slide()
```

Scaffold C-CHECKPOINT — A safe checkpoint respawn
Setup: Add this pattern to a separate Node2D level root with child Player using C-PLATFORM. Call set_checkpoint with a safe global position when a player reaches a checkpoint Area2D; call respawn when entering a fall zone. This code does not connect Area2D automatically; select the area body_entered signal in editor and call these methods from its handler after checking the player group. Respawn is deferred because a physics callback may be active.
```gdscript
extends Node2D
@onready var player: CharacterBody2D = $Player
var checkpoint: Vector2
func _ready() -> void:
    checkpoint = player.global_position
func set_checkpoint(safe_position: Vector2) -> void:
    checkpoint = safe_position
func respawn() -> void:
    _apply_respawn.call_deferred()
func _apply_respawn() -> void:
    player.global_position = checkpoint
    player.velocity = Vector2.ZERO
```

### Assignment
1. Audit every level object’s role and collider.
2. Test platform seams, side contacts and undersides with visible collision shapes.

### Acceptance checks
- Decoration does not block movement.
- No hidden collider edge catches the player at a seamless-looking join.

**Submit:** Collision-role table and repaired level checkpoint.

**Question:** Why should a checkpoint use a sensor instead of a wall body?

**Support:** Use one checkpoint on a broad platform and keep the camera fixed until respawn is reliable. Start with the first assigned task and re-run its acceptance test before adding the remaining feature.

**Optional extension:** Compare start-only retries with a midpoint checkpoint using the same route. Document one changed parameter, your prediction, and the observed effect; optional, not required for completion.

**Optional free reading:** [Your first 2D game](https://docs.godotengine.org/en/stable/getting_started/first_2d_game/index.html)

---

## VGC-L069 — Offer a documented assist option

**Objective:** Implement a gentle mode without changing the core learning objective.

**Time:** 55 minutes

### Instruction
An assist option can make a game more usable while preserving the programming task. Choose one: slightly slower horizontal speed, wider optional practice platforms, or checkpoint retries without a lives limit. Show the setting before play and describe what changes. Do not secretly change gravity or collision during a jump. A setting should be reversible and tested in both states. The assignment still requires understanding movement, collision and state; difficulty is not a measure of programming competence.

### Worked example
A checkpoint trigger and safe spawn marker serve different roles. The trigger notices arrival, while the marker specifies a collision-free return location above a platform.

Scaffold C-PLATFORM — A gravity-and-jump platform player
Setup: CharacterBody2D root Player, child CollisionShape2D RectangleShape2D size (24,32), no scale changes. Layer 1 mask 2. StaticBody2D floor layer 2 mask 1 with rectangular collider. Add Input Map move_left, move_right and jump bound to Space. Place player above floor, not intersecting it. Coordinates use positive y downward. Attach script to Player.
```gdscript
extends CharacterBody2D
@export var speed: float = 160.0
@export var gravity: float = 900.0
@export var jump_speed: float = 340.0
func _draw() -> void:
    draw_rect(Rect2(-12, -16, 24, 32), Color.SKY_BLUE)
    draw_line(Vector2(-8, -4), Vector2(8, -4), Color.BLACK, 2.0)
func _physics_process(delta: float) -> void:
    velocity.x = Input.get_axis("move_left", "move_right") * speed
    if not is_on_floor():
        velocity.y += gravity * delta
    if Input.is_action_just_pressed("jump") and is_on_floor():
        velocity.y = -jump_speed
    move_and_slide()
```

### Assignment
1. Implement one named assist option with a visible explanation.
2. Complete the route with assist on and off.

### Acceptance checks
- The setting changes only the documented behavior.
- Both settings remain completable and switching does not corrupt checkpoint state.

**Submit:** Assist implementation and two-mode test log.

**Question:** Why should assist mode not reduce a programming rubric score?

**Support:** Use one checkpoint on a broad platform and keep the camera fixed until respawn is reliable. Start with the first assigned task and re-run its acceptance test before adding the remaining feature.

**Optional extension:** Compare start-only retries with a midpoint checkpoint using the same route. Document one changed parameter, your prediction, and the observed effect; optional, not required for completion.

**Optional free reading:** [Your first 2D game](https://docs.godotengine.org/en/stable/getting_started/first_2d_game/index.html)

---

## VGC-L070 — Add a distinct goal state

**Objective:** Detect completion once and stop accepting conflicting gameplay.

**Time:** 55 minutes

### Instruction
Place a goal Area2D after the final platform. Its signal should notify the level manager only when a player enters and the phase is Play. On completion, show Delivered, stop Player physics, and offer Restart. Do not keep teleporting a completed player through a fall zone. Reuse the exclusive-state approach from Meteor Mail rather than introducing separate won/lost flags. Goal feedback should use text and an original symbol, not sound alone.

### Worked example
A checkpoint trigger and safe spawn marker serve different roles. The trigger notices arrival, while the marker specifies a collision-free return location above a platform.

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]
```

Scaffold C-CHECKPOINT — A safe checkpoint respawn
Setup: Add this pattern to a separate Node2D level root with child Player using C-PLATFORM. Call set_checkpoint with a safe global position when a player reaches a checkpoint Area2D; call respawn when entering a fall zone. This code does not connect Area2D automatically; select the area body_entered signal in editor and call these methods from its handler after checking the player group. Respawn is deferred because a physics callback may be active.
```gdscript
extends Node2D
@onready var player: CharacterBody2D = $Player
var checkpoint: Vector2
func _ready() -> void:
    checkpoint = player.global_position
func set_checkpoint(safe_position: Vector2) -> void:
    checkpoint = safe_position
func respawn() -> void:
    _apply_respawn.call_deferred()
func _apply_respawn() -> void:
    player.global_position = checkpoint
    player.velocity = Vector2.ZERO
```

### Assignment
1. Add goal detection, completion feedback and Restart.
2. Touch goal twice, then restart and complete again.

### Acceptance checks
- Completion occurs exactly once per round.
- Restart restores player motion and the initial checkpoint.

**Submit:** Relay Runner full-loop checkpoint and goal/reset tests.

**Question:** Why guard the goal handler if the player is disabled after winning?

**Support:** Use one checkpoint on a broad platform and keep the camera fixed until respawn is reliable. Start with the first assigned task and re-run its acceptance test before adding the remaining feature.

**Optional extension:** Compare start-only retries with a midpoint checkpoint using the same route. Document one changed parameter, your prediction, and the observed effect; optional, not required for completion.

**Optional free reading:** [Your first 2D game](https://docs.godotengine.org/en/stable/getting_started/first_2d_game/index.html)

---