Root cause: builder created plain Node instances for the state machine
and states, so _machine.player = self in PlayerMovementController
crashed with 'Invalid assignment ... on base object of type Node'.
Now each node gets its real script attached before _ready() runs.
player_movement_controller.gd: use Node + get_node() instead of
typed MovementStateMachine + $ shorthand so runtime set_script paths
don't crash on @implicit_ready
- state_wall_run.gd: typed ray_origin/ray_end as Vector3
- test_level_builder.gd: restructure builder to put MovementStateMachine
+ state children under Player, attach camera under Player too
- player_movement_controller.gd: @onready uses get_node so type is not inferred
- _build_player: creates Player (CharacterBody3D) with capsule,
MovementStateMachine + 6 state children, attaches movement script
- Calls player._ready() manually after set_script (GDScript
set_script does not auto-trigger _ready)
- Camera parented under Player so it follows movement
- Restores _build_camera() which was accidentally dropped
- test_level.tscn: minimal Node3D root (zero SubResource references)
- debug/test_level_builder.gd: runtime floor/walls/lighting/camera/UI
shapes/meshes created from BoxShape3D/BoxMesh — no .tscn subresources
- project.godot: revert features to 4.6 (installed build is 4.6.3)
- Removed all SubResource BoxShape3D references from test_level.tscn
- Changed PackedStringArray feature from 4.6 to 4.2
Scene is now pure nodes + transforms, no external resource IDs
- scenes/test_level/test_level.tscn — playable test environment (30x30 floor + 4 walls + ramp)
Floor at y=-1, Player spawn at (0, 1.5, 8), FpsCamera at head height (y=1.7)
DirectionalLight + WorldEnvironment + UI label overlay (speed/state/chain)
- debug/debug_test_env.sh — launch wrapper for manual playtesting
No code changes: raw physics testbed. Intended to be opened as first scene in Godot window.
Closes#2 (test-level scene task)
- state_dash.gd: Basis*Vector4 → Basis*Vector3 (no Vec4 in Godot 4.2)
- state_ground.gd: shape_owner_get_shape(0) → (0, 0); typed Variant vars; typed ray/normal
- state_slide.gd: same shape API fix + unique shape vars per branch
- state_wall_run.gd: split 'and' line into single typed bool expression