84 lines
2.4 KiB
GDScript
84 lines
2.4 KiB
GDScript
extends SceneTree
|
|
## Ragdoll throw visual test — triggers ragdoll on the matador and captures a
|
|
## frame strip so you can inspect the throw arc and settling.
|
|
##
|
|
## Run (needs a display for real screenshots):
|
|
## godot --script tests/ragdoll_throw_test.gd
|
|
##
|
|
## Outputs: tests/output/ragdoll_throw/frame_00..09.png
|
|
## Each frame is 0.2 s apart → strip covers 2 s of flight and tumble.
|
|
|
|
const OUTPUT_DIR := "res://tests/output/ragdoll_throw"
|
|
const BULL_SPEED := 22.0 # simulate a solid charge
|
|
|
|
const TRACKED_BONES: Array[StringName] = [&"chest", &"head", &"COG"]
|
|
|
|
|
|
func _init() -> void:
|
|
_run.call_deferred()
|
|
|
|
|
|
func _run() -> void:
|
|
DirAccess.make_dir_recursive_absolute(OUTPUT_DIR)
|
|
|
|
var scene_res := load("res://scene.tscn")
|
|
if not scene_res:
|
|
push_error("ragdoll_throw_test: failed to load scene.tscn")
|
|
quit(1)
|
|
return
|
|
|
|
var scene: Node = scene_res.instantiate()
|
|
root.add_child(scene)
|
|
|
|
# Let physics and AI settle
|
|
await create_timer(0.8).timeout
|
|
|
|
var matadors := get_nodes_in_group(&"matador")
|
|
if matadors.is_empty():
|
|
push_error("ragdoll_throw_test: no matadors in scene")
|
|
quit(1)
|
|
return
|
|
|
|
var mat := matadors[0] as Node3D
|
|
var spawn := mat.global_position
|
|
print("matador spawn: %s" % spawn)
|
|
|
|
# Throw toward +Z with a realistic charge speed
|
|
mat.call(&"_enter_ragdoll", Vector3(0.0, 0.0, 1.0), BULL_SPEED)
|
|
print("ragdoll triggered bull_speed=%.1f" % BULL_SPEED)
|
|
|
|
# Strip: 10 frames every 0.2 s
|
|
for i: int in range(10):
|
|
await create_timer(0.2).timeout
|
|
var t := (i + 1) * 0.2
|
|
|
|
var img: Image = root.get_viewport().get_texture().get_image()
|
|
if img:
|
|
img.save_png(OUTPUT_DIR + "/frame_%02d.png" % i)
|
|
|
|
var sim: Node = _find_class_recursive(mat, "PhysicalBoneSimulator3D")
|
|
var bone_info := ""
|
|
if sim:
|
|
for bone_name: StringName in TRACKED_BONES:
|
|
for child: Node in sim.get_children():
|
|
if child is PhysicalBone3D and \
|
|
(child as PhysicalBone3D).bone_name == bone_name:
|
|
var bp: Vector3 = (child as PhysicalBone3D).global_position
|
|
var dist: float = bp.distance_to(spawn)
|
|
bone_info += " %s y=%.2f dist=%.2f" % [bone_name, bp.y, dist]
|
|
|
|
print("t=%.1fs frame %02d%s" % [t, i, bone_info])
|
|
|
|
print("\nStrip saved → %s" % OUTPUT_DIR)
|
|
quit(0)
|
|
|
|
|
|
func _find_class_recursive(node: Node, class_name_str: String) -> Node:
|
|
if node.get_class() == class_name_str:
|
|
return node
|
|
for child: Node in node.get_children():
|
|
var r := _find_class_recursive(child, class_name_str)
|
|
if r:
|
|
return r
|
|
return null
|