# fly_dynamic_collision_test —— 40250 FlyingInstance 动态 Actor 碰撞回归。 # # 参考 FlyingInstance.cpp::Update: # collision sphere = max(move_distance * 2, configured radius) # hitonanothermonster -> HittedObjectSet 去重 -> OnExplodingAtAnotherTarget # pierce 后继续飞行,耗尽才爆炸。 extends SceneTree const FlyObject = preload("res://fly_object.gd") var _failures := 0 func _ck(condition: bool, message: String) -> void: if condition: return _failures += 1 printerr("FAIL: ", message) func _init() -> void: await _run() quit(1 if _failures else 0) func _run() -> void: await process_frame _test_two_actors_and_pierce() _test_same_actor_is_deduplicated() if _failures == 0: print("PASS: fly_dynamic_collision_test") func _new_manager() -> Array: var mount := Node3D.new() get_root().add_child(mount) var manager := FlyObject.new() manager.manual_step = true mount.add_child(manager) manager.setup(mount) return [manager, mount] func _test_two_actors_and_pierce() -> void: var fixture := _new_manager() var manager: FlyObject = fixture[0] var mount: Node3D = fixture[1] var first := Node3D.new() first.position = Vector3(0.0, 1.0, 5.0) get_root().add_child(first) var second := Node3D.new() second.position = Vector3(0.0, 1.0, 10.0) get_root().add_child(second) manager.set_actor_provider(func() -> Array: return [ {"vid": 200, "node": first, "center": first.position, "radius": 0.35}, {"vid": 300, "node": second, "center": second.position, "radius": 0.35}, ] ) var events: Array[int] = [] var data := FlyObject.FlyData.new() data.init_vel = 10.0 data.flat_range = 30.0 data.bomb_range = 0.05 data.collision_sphere_radius = 0.05 data.hit_on_another_monster = true data.pierce_count = 1 var inst = manager.spawn(Vector3(0.0, 1.0, 0.0), Vector3(0.0, 1.0, 30.0), false, data) inst.handler = func(event: String, _pos: Vector3, vid: int) -> void: if event == "at_another": events.append(vid) for _i in 100: if manager.active_count() == 0: break manager.step(0.1) _ck(events == [200, 300], "pierce projectile hits first and second Actor exactly once") _ck(manager.active_count() == 0, "non-piercing second Actor hit removes projectile") manager.clear_for_map_change() first.free() second.free() manager.free() mount.free() func _test_same_actor_is_deduplicated() -> void: var fixture := _new_manager() var manager: FlyObject = fixture[0] var mount: Node3D = fixture[1] var target := Node3D.new() target.position = Vector3(0.0, 1.0, 5.0) get_root().add_child(target) manager.set_actor_provider(func() -> Array: return [{"vid": 400, "node": target, "center": target.position, "radius": 0.35}] ) var events: Array[int] = [] var data := FlyObject.FlyData.new() data.init_vel = 10.0 data.flat_range = 12.0 data.bomb_range = 0.05 data.collision_sphere_radius = 0.05 data.hit_on_another_monster = true data.pierce_count = 2 var inst = manager.spawn(Vector3(0.0, 1.0, 0.0), Vector3(0.0, 1.0, 30.0), false, data) inst.handler = func(event: String, _pos: Vector3, vid: int) -> void: if event == "at_another": events.append(vid) for _i in 100: if manager.active_count() == 0: break manager.step(0.1) _ck(events == [400], "same dynamic Actor is blocked by HittedObjectSet") _ck(manager.active_count() == 0, "deduplicated projectile eventually expires") manager.clear_for_map_change() target.free() manager.free() mount.free()