extends SceneTree ## Thrown-spear hit test. The bull's body sits on collision layer BULL, so a spear whose mask ## only covered WORLD flew straight through it — every throw whiffed, even against a stationary ## bull. This launches a spear dead-on at a still fake bull and asserts the projectile masks BULL ## and actually lands the hit. Run: godot --headless --script res://tests/matador_spear_test.gd # physics_layers.gd is pure constants (safe to preload); spear_projectile.gd references the # Settings autoload, whose global identifier isn't registered when a --script entry compiles its # preloads — so it's loaded at runtime inside _run instead, once the autoloads exist. const PhysicsLayers = preload("res://physics_layers.gd") var _pass := 0 var _fail := 0 func _init() -> void: _run.call_deferred() func _ok(c: bool, m: String) -> void: if c: _pass += 1 print(" PASS: ", m) else: _fail += 1 print(" FAIL: ", m) func _run() -> void: # Stationary fake bull at the origin, on the BULL layer like the real one. var bull := CharacterBody3D.new() bull.collision_layer = PhysicsLayers.BULL bull.collision_mask = 0 bull.add_to_group(&"player") bull.set_script(load("res://tests/_fake_bull.gd")) var bcs := CollisionShape3D.new() var bshape := CapsuleShape3D.new() bshape.radius = 0.6 bshape.height = 1.4 bcs.shape = bshape bull.add_child(bcs) root.add_child(bull) bull.global_position = Vector3.ZERO await physics_frame # Launch a spear flat, dead-on from 3 m out; low gravity so the short flight stays level. var spear_script := load("res://spear_projectile.gd") var mesh := (load("res://Spear.tscn") as PackedScene).instantiate() as Node3D root.add_child(mesh) var origin := Vector3(0.0, 0.0, -3.0) var spear := spear_script.launch(root, mesh, origin, Vector3(0.0, 0.0, 12.0), 0.05) as RigidBody3D _ok(spear.collision_mask & PhysicsLayers.BULL != 0, "spear masks the BULL layer (can collide with the bull)") for i in 90: await physics_frame if bull.hits >= 1: break _ok(bull.hits >= 1, "thrown spear hits a stationary bull") _finish() func _finish() -> void: print("Results: %d passed, %d failed" % [_pass, _fail]) quit(1 if _fail > 0 else 0)