extends SceneTree var failures := 0 var starts := 0 var wins := 0 var losses := 0 func check(value: bool, message: String) -> void: if not value: failures += 1 push_error(message) func _initialize() -> void: call_deferred("run") func run() -> void: var g = load("res://games/space_invaders/SpaceInvaders.tscn").instantiate() root.add_child(g) g.set_physics_process(false) g.sound_enabled = false g.game_started.connect(func(): starts += 1) g.game_won.connect(func(): wins += 1) g.game_lost.connect(func(): losses += 1) check(g.aliens.size()==55 and g.shields.size()==4,"Initial fleet/shields") check(g.start_game() and not g.start_game(),"Start guard") g._physics_process(2.1) check(g.phase=="play" and starts==1,"Ready and event") check(g.fire() and not g.fire(),"One player shot") g.remove_shot() check(g.shot_count==1,"Shot sequence") var a: Vector2 = g.aliens[0].position var b: Vector2 = g.aliens[1].position g.march() check(g.aliens[0].position==a+Vector2(2,0) and g.aliens[1].position==b,"Ripple movement") for alien in g.aliens: alien.alive=false g.aliens[0].alive=true g.aliens[0].position=Vector2(208,100) g.fleet_cursor=0 g.march() check(g.fleet_direction==-1 and g.aliens[0].position.y==108,"Edge descent") var shield: Dictionary = g.shields[0] var point := Vector2(shield.position)+Vector2(12,4) check(g.shield_hit(point,true),"Shield collision") check(shield.image.get_pixel(12,4).a==0,"Destructible shield pixel") check(not g.shield_hit(point,true),"Hole allows shot through") g.new_wave() for alien in g.aliens: alien.alive=false g.aliens[0].alive=true g.aliens[0].position=Vector2(100,100) g.hit_pause=1 g.shot_active=true g.player_shot=Vector2(100,110) g.step_world(.05) check(not g.aliens[0].alive and g.score==10 and g.phase=="clear","Alien hit/clear") g._physics_process(1.6) check(wins==1 and not g.is_running,"Win event") g.start_game() g.waves_to_win=0 g.phase="clear" g.phase_time=0 g._physics_process(.01) check(g.wave==2 and g.aliens[44].position.y==96,"Next wave height") g.phase="play" g.lives=1 g.die() g._physics_process(1.6) check(losses==1 and g.phase=="lost","Loss event") g.start_game() g.add_score(1500) var lives: int = g.lives g.add_score(2000) check(lives==g.starting_lives+1 and g.lives==lives,"One bonus life") g.reset_game() g.high_score=9999 g.last_score=420 var original_starts := starts var original_wins := wins var original_losses := losses g.begin_demo() for i in range(1600): g._physics_process(1.0/60) check(not g.demo and not g.is_running and g.phase=="attract","Demo exit") check(g.high_score==9999 and g.score==420,"Demo score isolation") check(starts==original_starts and wins==original_wins and losses==original_losses,"Demo event isolation") g.begin_demo() check(g.start_game() and not g.demo and g.score==0,"Start interrupts demo") g.reset_game() check(g.phase=="attract" and not g.is_running,"Reset") g.start_game() g.phase="play" g.hit_pause=1 g.saucer_active=true g.saucer_x=100 g.shot_count=8 g.shot_active=true g.player_shot=Vector2(100,50) g.step_world(.025) check(g.score==300 and not g.saucer_active and not g.shot_active,"Saucer score sequence and collision") g.hit_pause=1 g.shot_delay=0 g.fire() g.player_shot=Vector2(16,180) g.bombs.clear() g.bombs.append({"position":Vector2(16,174),"kind":0}) g.step_world(.01) check(not g.shot_active and g.bombs.is_empty(),"Projectile interception") g.bombs.append({"position":Vector2(g.player_x,214),"kind":0}) g.step_world(.025) check(g.phase=="dead","Enemy projectile hits player") g._physics_process(1.6) g._physics_process(1.1) check(g.phase=="play" and g.bombs.is_empty(),"Respawn clears threats") for alien in g.aliens: alien.alive=false g.aliens[0].alive=true g.aliens[0].position=Vector2(100,216) g.fleet_cursor=0 g.march() check(g.phase=="lost" and not g.is_running,"Invasion is an immediate loss") g._physics_process(5.1) check(g.phase=="attract","Game over returns to attract") var definition = load("res://data/games/space_invaders.tres") check(definition.game_id==&"space_invaders" and definition.scene!=null,"Game resource") var database = load("res://data/project_database.tres") check(database.get_game(&"space_invaders")!=null,"Database registration") print("Space Invaders checks: ",failures," failures") g.free() quit(failures)