extends SceneTree # Headless gameplay test: run with # godot --headless -s res://tests/test_enemy_collision.gd # Verifies that an enemy touching a ship destroys that ship, is removed # from the fleet, while the enemy itself survives the touch (enemies only # die from being shot, not from ramming). const CHECK_DELAY: float = 0.05 var main_scene: Node var fleet: Node var enemy: Node var target_ship: Node var elapsed: float = 0.0 var started: bool = false func _initialize() -> void: var packed: PackedScene = load("res://Main.tscn") main_scene = packed.instantiate() root.add_child(main_scene) fleet = main_scene.get_node("Fleet") func _physics_process(delta: float) -> bool: if not started: # Disabling EnemySpawner in _initialize() doesn't reliably stick - # a node's set_process(false) call made before it has fully # finished entering the tree can get silently reset once the # engine's own (deferred) tree-entry finalization runs, which # happens strictly after _ready(). Here, at the point _ready() is # already confirmed complete, it's safe. main_scene.get_node("EnemySpawner").set_process(false) target_ship = fleet.ships[0] var enemy_scene: PackedScene = load("res://Enemy.tscn") enemy = enemy_scene.instantiate() enemy.position = target_ship.position main_scene.add_child(enemy) started = true return false elapsed += delta if elapsed >= CHECK_DELAY: _finish() return true return false func _finish() -> void: var ship_destroyed: bool = not is_instance_valid(target_ship) var ship_removed_from_fleet: bool = fleet.ships.find(target_ship) == -1 var fleet_count_ok: bool = fleet.ships.size() == 4 var enemy_survived: bool = is_instance_valid(enemy) and enemy.hp > 0 print("ship_destroyed=%s ship_removed_from_fleet=%s ships_remaining=%d enemy_survived=%s" % [ ship_destroyed, ship_removed_from_fleet, fleet.ships.size(), enemy_survived ]) if ship_destroyed and ship_removed_from_fleet and fleet_count_ok and enemy_survived: print("TEST_ENEMY_COLLISION: PASS") quit(0) else: print("TEST_ENEMY_COLLISION: FAIL") quit(1)