Video Game Design and Coding · PLECK lesson
PLECK lesson 112 · suggested week 23, day 2
Write a small best-score save
Objective. Use FileAccess and report failure honestly.
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.
JSON, user://, schema validation and safe failure
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-L111.
C-SAVE writes a tiny dictionary through JSON.stringify to a course-specific user:// file. FileAccess.open can fail, so check for null and return false rather than showing a false success message. Clamp a score before writing. Call write_best only after a valid round result or an explicit Save action, not every rendered frame. The baseline read prints a value but does not modify the file. Desktop persistence is the required path; browser storage has additional restrictions.
Worked example
A validated save contains known scalar fields and a version. An array instead of a dictionary is syntactically valid JSON but should still be rejected by the schema. Scaffold C-SAVE — Small, validated local best-score save Setup: Attach to Node SaveLab. Only saves version and integer best score to user://course_best.json. No nodes, paths from a save file, private data or scripts are loaded. Functions return safe defaults for missing/invalid data. Test in desktop editor, using a course-only filename so existing game saves are untouched. Do not edit unrelated user:// files. ```gdscript extends Node const PATH: String = "user://course_best.json" func write_best(best: int) -> bool: var file := FileAccess.open(PATH, FileAccess.WRITE) if file == null: return false file.store_string(JSON.stringify({"version": 1, "best": clampi(best, 0, 999999)})) file.close() return true func read_best() -> int: if not FileAccess.file_exists(PATH): return 0 var file := FileAccess.open(PATH, FileAccess.READ) if file == null: return 0 var text: String = file.get_as_text() file.close() var parser := JSON.new() if parser.parse(text) != OK: return 0 var parsed: Variant = parser.data if not parsed is Dictionary: return 0 var data: Dictionary = parsed if data.get("version", 0) != 1: return 0 var best: Variant = data.get("best", 0) if not (best is int or best is float): return 0 return clampi(int(best), 0, 999999) func _ready() -> void: print("Saved best: ", read_best()) ```
Small, validated local best-score save
GDScript (Godot 4, not Scratch, Python, JavaScript or C#). Scaffold C-SAVE. Copy starts from this text. The desk does not run it.
Scene and node setup
Attach to Node SaveLab. Only saves version and integer best score to user://course_best.json. No nodes, paths from a save file, private data or scripts are loaded. Functions return safe defaults for missing/invalid data. Test in desktop editor, using a course-only filename so existing game saves are untouched. Do not edit unrelated user:// files.
extends Node
const PATH: String = "user://course_best.json"
func write_best(best: int) -> bool:
var file := FileAccess.open(PATH, FileAccess.WRITE)
if file == null:
return false
file.store_string(JSON.stringify({"version": 1, "best": clampi(best, 0, 999999)}))
file.close()
return true
func read_best() -> int:
if not FileAccess.file_exists(PATH):
return 0
var file := FileAccess.open(PATH, FileAccess.READ)
if file == null:
return 0
var text: String = file.get_as_text()
file.close()
var parser := JSON.new()
if parser.parse(text) != OK:
return 0
var parsed: Variant = parser.data
if not parsed is Dictionary:
return 0
var data: Dictionary = parsed
if data.get("version", 0) != 1:
return 0
var best: Variant = data.get("best", 0)
if not (best is int or best is float):
return 0
return clampi(int(best), 0, 999999)
func _ready() -> void:
print("Saved best: ", read_best())
Checks to run in the editor
- Missing or malformed JSON returns zero without crashing.
- Write 42, stop, restart: read 42.
- String best and unknown version return zero.
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.
Write a small best-score save — evidence task
- 1. Run the C-SAVE lab and call write_best with 42 using a temporary _ready test.
- 2. Stop, remove the write call and relaunch to read the saved value.
Deliverable. Best-score lab source and stop/relaunch evidence.
Acceptance checks
- VGC-L112-T1. Relaunch reads 42 without rewriting it.
- VGC-L112-T2. The caller checks the returned success Boolean.
Understanding question. Why remove the test write before verifying a load?
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 the course-specific save filenames in C-SAVE and C-STATE-SAVE. Never edit unrelated game saves or load scripts from save data. Start with the first assigned task and re-run its acceptance test before adding the remaining feature.
Optional extra. Add a new fixed scalar field with a safe default and explicit validation. Document one changed parameter, your prediction, and the observed effect; optional, not required for completion.
- Godot step by step: nodes, scenes, GDScript, input, signals
Free public documentation, no account. Same class help is available within the desktop editor.
· Opening this link does not submit the lesson. - Saving games: FileAccess and JSON
Free public documentation, no account.
· Opening this link does not submit the lesson.
Name ____________________ Date ____________________