OverviewFilesCommitsIssuesDocsReleasesPeers

hyper-tps / scenes / test / gate_curve_point_handles.gd

74 lines · gd ref:
extends Node
## GATE — set_curve_point RE-DERIVES HANDLES (#129 deferred bug; docs §14.2 note).
## Writing only `p` left a point's stored handles where they were, so an auto / vector
## point moved that way bent its spans. The handles of auto / vector points (the moved one
## and its neighbours) are re-derived in the same gesture; aligned / free keep theirs.
##   P1  auto: after moving point 1, every point's handles = auto_handles of the new points
##   P2  ... in ONE gesture
##   P3  a FREE point keeps its stored handles
##
## RUN AS A SCENE: "$HYPER_TPS_GODOT" --headless res://scenes/test/gate_curve_point_handles.tscn

var fails := 0
var checks := 0
var map: Node3D


func _ok(what: String, cond: bool, note: Variant = "") -> void:
	checks += 1
	if not cond:
		fails += 1
	print("  %-64s %s  %s" % [what, "OK" if cond else "**FAIL**", str(note)])


func _ready() -> void:
	var gs: Node = get_tree().root.get_node_or_null("/root/GameState")
	gs.route("world:level:*", 1, "peer")
	var keet: Node = get_tree().root.get_node_or_null("/root/KeetService")
	if keet != null:
		keet.current_member_id = "gate-author"
	get_tree().root.get_node("/root/GameMode").set_mode("build")
	map = (load("res://scenes/maps/map_dev_test.tscn") as PackedScene).instantiate()
	add_child(map)
	for i in 6:
		await get_tree().process_frame
	_run()
	get_tree().root.get_node("/root/GameMode").set_mode("play")
	if checks < 3:
		print("  **FAIL** only %d checks ran -- setup died before the assertions" % checks)
		fails += 1
	print("\nGATE curve_point_handles: %s (%d checks, %d failed)" % ["PASS" if fails == 0 else "FAIL", checks, fails])
	get_tree().quit(0 if fails == 0 else 1)


func _same(a: Array, b: Array) -> bool:
	for i in a.size():
		for k: String in ["h_in", "h_out"]:
			if not ((a[i] as Dictionary)[k] as Vector3).is_equal_approx((b[i] as Dictionary)[k]):
				return false
	return true


func _run() -> void:
	var persist: Node = map.get("_persist")
	var O := Vector3(90.13, 1.0, 90.29)
	var c: String = map.create_curve([CurveMath.point(O), CurveMath.point(O + Vector3(3.1, 0, 0)),
		CurveMath.point(O + Vector3(6.3, 0, 0)), CurveMath.point(O + Vector3(9.2, 0, 1.1))], false, "H")
	var g0: int = (persist.gestures(true) as Array).size()
	map.set_curve_point(c, 1, {"p": O + Vector3(3.1, 0, 2.4)})
	var pts: Array = map.curve_states()[c]["points"]
	var want: Array = CurveMath.auto_handles(pts, false)
	_ok("P1 auto points' handles are re-derived from the new points", _same(pts, want),
		[pts[1]["h_out"], want[1]["h_out"]])
	_ok("P2 ... in ONE gesture", (persist.gestures(true) as Array).size() == g0 + 1)
	# A FREE point keeps its handles.
	var f: String = map.create_curve([CurveMath.point(O + Vector3(0, 0, 9)), CurveMath.point(O + Vector3(3, 0, 9)),
		CurveMath.point(O + Vector3(6, 0, 9))], false, "F")
	var q1: Dictionary = (map.curve_states()[f]["points"] as Array)[1].duplicate()
	q1["handle"] = "free"
	q1["h_out"] = Vector3(0.0, 0.7, 0.0)
	map.set_curve_point(f, 1, q1)
	map.set_curve_point(f, 1, {"p": O + Vector3(3, 0, 10.5)})
	var hf: Vector3 = (map.curve_states()[f]["points"] as Array)[1]["h_out"]
	_ok("P3 a free point keeps its stored handle", hf.is_equal_approx(Vector3(0.0, 0.7, 0.0)), hf)