Files
Papay-Shooter/debug/travel_dir_check.gd
T
2026-08-09 01:31:44 -04:00

110 lines
3.3 KiB
GDScript

extends SceneTree
## Regression for authored directional locomotion.
##
## The old test expected one forward run to be procedurally yawed or reversed.
## The runtime now blends separate forward/back/left/right source cycles. This
## gate verifies that physical direction enters that authored BlendSpace, stride
## speed stays calibrated, and the feet actually move in every cardinal case.
## The real controller ground speed, not a convenient library-preview speed.
## This is the failure mode the test exists to catch: the old lateral cycle was
## technically "matched" at 5 m/s but exploded to 6.1x playback in gameplay.
const SPEED := 11.0
const DT := 1.0 / 60.0
const SETTLE_FRAMES := 45
const SAMPLE_FRAMES := 24
const CASES := [
["forward", 0.0, 1.0, "Sprint"],
["backward", 0.0, -1.0, "RunBackward"],
["left", -1.0, 0.0, "RunLeft"],
["right", 1.0, 0.0, "RunRight"],
["forward-right", 1.0, 1.0, ""],
["back-left", -1.0, -1.0, ""],
]
var _failures := 0
func _initialize() -> void:
call_deferred("_run")
func _run() -> void:
await process_frame
var args := OS.get_cmdline_user_args()
var path: String = args[0] if not args.is_empty() \
else "res://assets/characters/skins/taila.glb"
var scene := Node3D.new()
root.add_child(scene)
current_scene = scene
var model := SkinnedPlayerModel.new()
model.model_path = path
scene.add_child(model)
for _frame in 60:
await process_frame
if not model.loaded or model.skeleton == null:
_expect(false, "the authored character loads")
_done()
return
if model._spring_mod:
model._spring_mod.lod = 3
model._spring_mod = null
model.set_process(false)
var foot := model._role_bone("foot.L", ["foot.L", "LeftFoot", "Left ankle"])
_expect(foot >= 0, "a foot bone resolves")
for test_case in CASES:
var direction := Vector2(float(test_case[1]), float(test_case[2])).normalized()
for _frame in SETTLE_FRAMES:
model.set_locomotion(direction.x, direction.y, 0.0)
model.update_state("ground", SPEED, false)
model._process(DT)
await process_frame
var blend := model.locomotion_blend_debug()
_expect(blend.length() > 0.01 and blend.normalized().dot(direction) > 0.999,
"%s drives the authored BlendSpace in the physical direction"
% String(test_case[0]))
_expect(absf(model.locomotion_effective_speed_debug() - SPEED) < 0.25,
"%s authored stride matches %.1f m/s"
% [String(test_case[0]), SPEED])
var expected_clip := String(test_case[3])
if not expected_clip.is_empty():
_expect(model.current_clip_debug() == expected_clip,
"%s selects %s" % [String(test_case[0]), expected_clip])
if foot >= 0:
var start := model.skeleton.get_bone_pose_rotation(foot)
var greatest := 0.0
for _frame in SAMPLE_FRAMES:
model.set_locomotion(direction.x, direction.y, 0.0)
model.update_state("ground", SPEED, false)
model._process(DT)
await process_frame
greatest = maxf(greatest, start.angle_to(
model.skeleton.get_bone_pose_rotation(foot)))
_expect(greatest > 0.03,
"%s uses a moving authored foot cycle (%.3f rad)"
% [String(test_case[0]), greatest])
model.queue_free()
_done()
func _expect(ok: bool, description: String) -> void:
if ok:
print(" OK: ", description)
else:
printerr(" FAIL: ", description)
_failures += 1
func _done() -> void:
print("\n=== AUTHORED DIRECTION SUMMARY ===")
print("Failures: %d" % _failures)
quit(1 if _failures > 0 else 0)