Video Game Design and Coding

Week 21 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 21 — Accessibility and responsible interaction

## VGC-L101 — Audit barriers instead of labeling a game accessible

**Objective:** Describe specific tested features and limitations.

**Time:** 55 minutes

### Instruction
Accessibility is a set of concrete design decisions, not a decorative badge. Audit your game for keyboard control, readable text, non-color cues, sound alternatives, pause and motion settings. For each feature write a test and a remaining limitation. A game can improve without claiming it serves every player. Do not ask a tester to disclose a diagnosis. Let people choose settings without justification and accept text-based explanations instead of mandatory recordings.

### Worked example
A barrier audit might test whether Tab can reach Restart. The result is a specific supported capability, not a claim that every assistive technology is supported.

### Assignment
1. Create a six-feature barrier audit with one test per feature.
2. Choose the two highest-impact fixes.

### Acceptance checks
- Claims describe tested behavior rather than universal compliance.
- No test asks for health or identity information.

**Submit:** Accessibility audit and prioritized fixes.

**Question:** Why is “fully accessible” too broad without evidence?

**Support:** Test one barrier at a time: keyboard only, muted audio, reduced motion and enlarged text. Keep a checklist of actual results. Start with the first assigned task and re-run its acceptance test before adding the remaining feature.

**Optional extension:** Let a willing tester choose a comfort setting before the test without asking why they need it. 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), [Exporting for the Web](https://docs.godotengine.org/en/stable/tutorials/export/exporting_for_web.html)

---

## VGC-L102 — Make keyboard focus visible and complete

**Objective:** Test every menu action without a pointing device.

**Time:** 55 minutes

### Instruction
List all menu buttons and settings, then navigate with Tab, Shift-Tab and the accept key. Focus should be visible, order should match reading flow, and a hidden control should not trap navigation. On a newly shown screen, set initial focus to the first meaningful action. Keep gameplay movement actions separate from UI navigation so changing a movement key does not silently remove menu control. If a scene has no menus, add a minimal start/restart panel to test this skill.

### Worked example
A barrier audit might test whether Tab can reach Restart. The result is a specific supported capability, not a claim that every assistive technology is supported.

Scaffold C-DIALOGUE — Data-driven branching dialogue without personal data
Setup: Create Control root Dialogue with VBoxContainer Box containing Label Line and Buttons A and B. Set Box anchors to full rect; Line autowrap if needed. Attach script to Dialogue. Data keys are fictional scene IDs. All three screens can fit in 640x360. This is a self-contained example; replace story text in the assignment.
```gdscript
extends Control
var page: String = "start"
var story: Dictionary = {
    "start": {"text": "Two paths enter the archive.", "choices": [["Ask the keeper", "keeper"], ["Read a sign", "sign"]]},
    "keeper": {"text": "The keeper offers a map.", "choices": [["Return", "start"]]},
    "sign": {"text": "Quiet room to the east.", "choices": [["Return", "start"]]}
}
func _ready() -> void:
    $Box/A.pressed.connect(_choose.bind(0))
    $Box/B.pressed.connect(_choose.bind(1))
    _show()
func _show() -> void:
    var entry: Dictionary = story[page]
    $Box/Line.text = entry["text"]
    var buttons: Array[Button] = [$Box/A, $Box/B]
    for i in range(buttons.size()):
        buttons[i].visible = i < entry["choices"].size()
        if buttons[i].visible:
            buttons[i].text = entry["choices"][i][0]
    $Box/A.grab_focus()
func _choose(index: int) -> void:
    var choices: Array = story[page]["choices"]
    if index < 0 or index >= choices.size():
        return
    page = str(choices[index][1])
    _show()
```

Scaffold C-PAUSE — Pause with an always-processing resume control
Setup: Node2D World root has CanvasLayer HUD with Button Pause, plus normal gameplay children. Set Pause button Process > Mode to Always in Inspector; leave World and gameplay as Inherit/Pausable. Attach script to World; merge into its existing _ready if present. Signal callbacks still work from the always-processing button. Label text starts Pause.
```gdscript
extends Node2D
func _ready() -> void:
    $HUD/Pause.pressed.connect(_toggle_pause)
func _toggle_pause() -> void:
    get_tree().paused = not get_tree().paused
    $HUD/Pause.text = "Resume" if get_tree().paused else "Pause"
```

### Assignment
1. Audit and repair focus for every menu control.
2. Complete start, pause, resume, settings and restart with keyboard only where those controls exist.

### Acceptance checks
- Every available control can be reached and activated.
- Focus does not remain on a hidden screen.

**Submit:** Keyboard-only navigation log and repaired UI.

**Question:** Why is a visible focus indicator important?

**Support:** Test one barrier at a time: keyboard only, muted audio, reduced motion and enlarged text. Keep a checklist of actual results. Start with the first assigned task and re-run its acceptance test before adding the remaining feature.

**Optional extension:** Let a willing tester choose a comfort setting before the test without asking why they need it. 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), [Exporting for the Web](https://docs.godotengine.org/en/stable/tutorials/export/exporting_for_web.html)

---

## VGC-L103 — Offer comfort settings with honest behavior

**Objective:** Implement two reversible settings and verify their actual effect.

**Time:** 55 minutes

### Instruction
Choose two settings appropriate to your game, such as mute, reduced motion, enlarged text or gentle difficulty. Give each a clear label and explanation. The setting must change behavior, not merely an icon. Test on, off and switching during a safe moment. Do not make essential information disappear in a comfort mode. Persisting settings is optional until the save unit; for now describe that they reset when the game restarts if that is what happens.

### Worked example
A barrier audit might test whether Tab can reach Restart. The result is a specific supported capability, not a claim that every assistive technology is supported.

Scaffold C-AUDIO — Local audio playback with a reversible mute
Setup: Create Control AudioLab with Button Play and CheckButton Mute. Child AudioStreamPlayer Sound: copy the supplied student-support/audio/course-tap.wav into your project audio folder and assign it (or another short original WAV/OGG), autoplay Off, volume_db -12. Attach script to AudioLab. Recording is optional: a teacher-provided original file is equivalent. No microphone or face recording is required and all recording stays private.
```gdscript
extends Control
func _ready() -> void:
    $Play.pressed.connect(_play)
    $Mute.toggled.connect(_mute)
func _play() -> void:
    if not $Mute.button_pressed:
        $Sound.play()
func _mute(enabled: bool) -> void:
    if enabled:
        $Sound.stop()
```

Scaffold C-TWEEN — Animate only a visual child
Setup: Create Node2D root Visual under a stationary physics actor, attach this script to Visual and keep its parent collider unchanged. Draw a small circle. A Tween interpolates properties over seconds; this is a visual pulse, not a flashing effect. Use modest scale changes and disable it in a reduced-motion setting.
```gdscript
extends Node2D
var pulse: Tween
func _draw() -> void:
    draw_circle(Vector2.ZERO, 10.0, Color.GOLD)
func _ready() -> void:
    pulse = create_tween().set_loops()
    pulse.tween_property(self, "scale", Vector2(1.08, 1.08), 0.6)
    pulse.tween_property(self, "scale", Vector2.ONE, 0.6)
func stop_motion() -> void:
    if pulse != null:
        pulse.kill()
    scale = Vector2.ONE
```

### Assignment
1. Implement two reversible comfort settings.
2. Test both states and document whether they persist between rounds.

### Acceptance checks
- Each setting changes only its stated behavior.
- All essential information remains available in every combination.

**Submit:** Settings checkpoint and four-combination test table.

**Question:** Why document whether settings persist?

**Support:** Test one barrier at a time: keyboard only, muted audio, reduced motion and enlarged text. Keep a checklist of actual results. Start with the first assigned task and re-run its acceptance test before adding the remaining feature.

**Optional extension:** Let a willing tester choose a comfort setting before the test without asking why they need it. 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), [Exporting for the Web](https://docs.godotengine.org/en/stable/tutorials/export/exporting_for_web.html)

---

## VGC-L104 — Remove manipulative and privacy-invasive patterns

**Objective:** Design clear exits and fictional data without telemetry.

**Time:** 55 minutes

### Instruction
A student game does not need ads, analytics, account creation, loot purchases or a public leaderboard. Use a local best score under a fictional label instead of collecting real names. Give the player an obvious way to stop or return to the title. Avoid countdown pressure for purchases, misleading buttons or rewards that require sharing. If a lesson asks for testing, collect anonymous task observations only. Privacy is easier to protect when unnecessary data is never requested in the first place.

### Worked example
A barrier audit might test whether Tab can reach Restart. The result is a specific supported capability, not a claim that every assistive technology is supported.

### Assignment
1. Audit the game for personal-data requests, misleading controls and forced sharing.
2. Write a plain-language privacy note stating what the local game stores or does not store.

### Acceptance checks
- No real personal data or public publication is required.
- Exit/restart controls say what they do.

**Submit:** Responsible-design audit and readme privacy note.

**Question:** Why prefer not collecting data over promising to protect unnecessary data?

**Support:** Test one barrier at a time: keyboard only, muted audio, reduced motion and enlarged text. Keep a checklist of actual results. Start with the first assigned task and re-run its acceptance test before adding the remaining feature.

**Optional extension:** Let a willing tester choose a comfort setting before the test without asking why they need it. 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), [Exporting for the Web](https://docs.godotengine.org/en/stable/tutorials/export/exporting_for_web.html)

---

## VGC-L105 — Release an accessibility revision privately

**Objective:** Compare a revised artifact against the earlier baseline.

**Time:** 55 minutes

### Instruction
Create a separate accessibility edition of the midyear game. Keep the baseline for comparison. Run the original eight minimum tests plus keyboard, muted, non-color, reduced-motion and text-layout checks appropriate to your design. Report improvements with evidence and list unresolved barriers. Packaging is private: submit source and a readme to the teacher, not a public social account. A private playthrough may demonstrate changes but the source artifact remains necessary.

### Worked example
A barrier audit might test whether Tab can reach Restart. The result is a specific supported capability, not a claim that every assistive technology is supported.

Scaffold C-TESTS — A tiny pure-function test harness
Setup: Attach to Node TestLab. If using command line, create a separate SceneTree harness rather than running this Node script with --script. Run current TestLab scene in editor; assert reports a failed condition in Debugger. No external test framework or package is needed.
```gdscript
extends Node
func bounded_score(old_score: int, change: int) -> int:
    return clampi(old_score + change, 0, 999)
func _ready() -> void:
    assert(bounded_score(10, 2) == 12)
    assert(bounded_score(0, -3) == 0)
    assert(bounded_score(998, 9) == 999)
    print("3 score checks passed")
```

### Assignment
1. Package the revised source and a before/after barrier table.
2. Restore and run core plus accessibility regression checks.

### Acceptance checks
- Core gameplay still passes.
- Every claimed accessibility improvement has a corresponding test result.

**Submit:** Accessibility-edition source artifact and comparison report.

**Question:** Can an accessibility fix create a regression?

**Support:** Test one barrier at a time: keyboard only, muted audio, reduced motion and enlarged text. Keep a checklist of actual results. Start with the first assigned task and re-run its acceptance test before adding the remaining feature.

**Optional extension:** Let a willing tester choose a comfort setting before the test without asking why they need it. 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), [Exporting for the Web](https://docs.godotengine.org/en/stable/tutorials/export/exporting_for_web.html)

---