spaceship/tests/test_crafter_animation.gd

121 lines
4.4 KiB
GDScript3
Raw Normal View History

extends SceneTree
# Headless gameplay test: run with
# godot --headless -s res://tests/test_crafter_animation.gd
# The ship crafter is drawn as a factory with a hull being assembled on the
# line. Verifies:
# 1. a crafter spawned the normal way (BuildingField, from GameState)
# actually animates - the animation is what tells the player what the
# building does. The mothership animates too (reactor core, orbiting
# satellites)
# 2. the command centre stays static, because per-frame redraws of art
# that never changes were a measurable framerate cost earlier on
# 3. the hull assembles progressively over the cycle rather than popping
# in whole, and every piece is on before the assembly phase ends
# 4. the cycle loops without anim_time growing without bound
var scene: Node
var game_state: Node
var field: Node
var stage: int = 0
var elapsed: float = 0.0
var crafter: Node2D
var time_at_start: float = 0.0
func _initialize() -> void:
game_state = root.get_node("GameState")
game_state.rocks = 200
game_state.buildings.clear()
game_state.extractors.clear()
scene = load("res://Main.tscn").instantiate()
root.add_child(scene)
field = scene.get_node("BuildingField")
func _find(type: String) -> Node2D:
for b in field.spawned:
if is_instance_valid(b) and b.building_type == type:
return b
return null
func _process(delta: float) -> bool:
elapsed += delta
match stage:
0:
scene.get_node("AsteroidField").set_process(false)
scene.get_node("EnemySpawner").set_process(false)
field.place(GameState.BUILDING_SHIP_CRAFTER, Vector2(500.0, 0.0))
field.place(GameState.BUILDING_MOTHERSHIP, Vector2(-500.0, 0.0))
field.place(GameState.BUILDING_COMMAND_CENTER, Vector2(0.0, 500.0))
elapsed = 0.0
stage = 1
return false
1:
# Spawning is deferred, so give the tree a frame to attach them.
if elapsed < 0.2:
return false
var crafter_building: Node2D = _find(GameState.BUILDING_SHIP_CRAFTER)
if crafter_building == null:
print("TEST_CRAFTER_ANIMATION: FAIL (crafter never spawned)")
quit(1)
return true
crafter = crafter_building.visual
var animated: bool = crafter.is_processing()
var mothership_building: Node2D = _find(GameState.BUILDING_MOTHERSHIP)
var mothership: Node2D = mothership_building.visual if mothership_building != null else null
var mothership_animates: bool = mothership != null and mothership.is_processing()
var command_building: Node2D = _find(GameState.BUILDING_COMMAND_CENTER)
var command: Node2D = command_building.visual if command_building != null else null
var command_static: bool = command != null and not command.is_processing()
print("crafter animates=%s mothership animates=%s command centre static=%s" % [
animated, mothership_animates, command_static
])
if not (animated and mothership_animates and command_static):
print("TEST_CRAFTER_ANIMATION: FAIL (wrong buildings are animating)")
quit(1)
return true
# --- the hull assembles piece by piece ------------------------
var total: int = crafter.SHIP_PARTS.size()
var counts: Array = []
for p in [0.0, 0.1, 0.35, 0.55, 0.9, 1.0]:
counts.append(crafter.attached_part_count(p))
var progressive: bool = counts[0] == 0 and counts[-1] == total
for i in range(1, counts.size()):
if counts[i] < counts[i - 1]:
progressive = false
# Nothing may still be missing when the welding phase ends, or
# the hull would launch half-built.
var complete_before_launch: bool = crafter.attached_part_count(1.0) == total
print("parts attached across the phase: %s (of %d) progressive=%s" % [
counts, total, progressive
])
if not (progressive and complete_before_launch and counts[1] < total):
print("TEST_CRAFTER_ANIMATION: FAIL (hull does not build up gradually)")
quit(1)
return true
time_at_start = crafter.anim_time
elapsed = 0.0
stage = 2
return false
2:
if elapsed < 0.4:
return false
var advanced: bool = crafter.anim_time != time_at_start
var bounded: bool = crafter.anim_time >= 0.0 and crafter.anim_time < crafter.CYCLE
print("anim_time %.3f -> %.3f (cycle %.2f) advanced=%s bounded=%s" % [
time_at_start, crafter.anim_time, crafter.CYCLE, advanced, bounded
])
if advanced and bounded:
print("TEST_CRAFTER_ANIMATION: PASS")
quit(0)
else:
print("TEST_CRAFTER_ANIMATION: FAIL (animation clock stalled or ran away)")
quit(1)
return true
return false