5f6258e3d4
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
167 lines
4.7 KiB
GDScript
167 lines
4.7 KiB
GDScript
extends SceneTree
|
|
## 地面单位回归测试(时间驱动):
|
|
## A) 独立堡垒:随地面滚动(~120px/s)、有开火产出敌弹
|
|
## B) Game 集成:堡垒击杀 +300、船击杀 +800
|
|
## C) 碰撞规则:玩家机体叠在堡垒上不掉命;玩家子弹真实命中堡垒
|
|
## 运行:godot --headless -s tests/ground_test.gd
|
|
|
|
const GLOBAL_TIMEOUT := 25.0
|
|
|
|
var _phase := 0
|
|
var _step := 0
|
|
var _phase_time := 0.0
|
|
var _time := 0.0
|
|
var _fortress: EnemyFortress
|
|
var _ship: EnemyShip
|
|
var _game: Game
|
|
var _bullets: Node2D
|
|
var _start_y := 0.0
|
|
var _bullet_time := 0.0
|
|
var _score_before := 0
|
|
var _lives_before := 3
|
|
var _fails: Array[String] = []
|
|
|
|
|
|
func _initialize() -> void:
|
|
_bullets = Node2D.new()
|
|
_bullets.add_to_group("enemy_bullets")
|
|
root.add_child(_bullets)
|
|
_fortress = EnemyFortress.new()
|
|
_fortress.setup(270.0, 200.0, 1.0)
|
|
root.add_child(_fortress)
|
|
_start_y = 200.0
|
|
print("[ground_test] phase A: standalone fortress")
|
|
|
|
|
|
func _fail(msg: String) -> void:
|
|
_fails.append(msg)
|
|
print("[FAIL] " + msg)
|
|
|
|
|
|
func _next_phase() -> void:
|
|
_phase += 1
|
|
_step = 0
|
|
_phase_time = 0.0
|
|
|
|
|
|
func _restart_step() -> void:
|
|
_step += 1
|
|
_phase_time = 0.0
|
|
|
|
|
|
func _finish() -> bool:
|
|
if _fails.is_empty():
|
|
print("[ground_test] PASS")
|
|
else:
|
|
print("[ground_test] FAIL: %d issue(s)" % _fails.size())
|
|
quit(0 if _fails.is_empty() else 1)
|
|
return true
|
|
|
|
|
|
## 清场(敌机+敌弹),保证后续断言确定性
|
|
func _clear_field() -> void:
|
|
for enemy in _game._enemies.get_children():
|
|
(enemy as Node).queue_free()
|
|
for bullet in _game._enemy_bullets.get_children():
|
|
bullet.queue_free()
|
|
|
|
|
|
func _process(delta: float) -> bool:
|
|
_time += delta
|
|
if _time > GLOBAL_TIMEOUT:
|
|
_fail("global timeout in phase %d" % _phase)
|
|
return _finish()
|
|
|
|
_phase_time += delta
|
|
match _phase:
|
|
0:
|
|
if _bullets.get_child_count() > 0:
|
|
_bullet_time += delta
|
|
if _phase_time >= 4.0:
|
|
var moved := _fortress.position.y - _start_y
|
|
if moved < 380.0 or moved > 620.0:
|
|
_fail("fortress scroll wrong: moved %.0f px in 4s (expect ~480)" % moved)
|
|
elif _bullet_time < 0.3:
|
|
_fail("fortress fired too little: %.2fs" % _bullet_time)
|
|
else:
|
|
print("[ground_test] fortress scroll+fire ok (moved %.0f px, bullet %.1fs)" % [moved, _bullet_time])
|
|
_fortress.apply_damage(999)
|
|
_next_phase()
|
|
1:
|
|
if not is_instance_valid(_fortress):
|
|
_next_phase()
|
|
elif _phase_time > 2.0:
|
|
_fail("fortress not freed after kill")
|
|
_next_phase()
|
|
2:
|
|
if _game == null:
|
|
_game = (load("res://scenes/game.tscn") as PackedScene).instantiate()
|
|
root.add_child(_game)
|
|
elif _game._enemies != null:
|
|
_ship = EnemyShip.new()
|
|
_ship.setup(270.0, 300.0, 1.0)
|
|
_game._enemies.add_child(_ship)
|
|
var f2 := EnemyFortress.new()
|
|
f2.setup(150.0, 300.0, 1.0)
|
|
_game._enemies.add_child(f2)
|
|
_score_before = _game.score
|
|
f2.apply_damage(999)
|
|
_next_phase()
|
|
3:
|
|
if _phase_time >= 0.6:
|
|
if _game.score != _score_before + 300:
|
|
_fail("fortress score: %d -> %d (expected +300)" % [_score_before, _game.score])
|
|
else:
|
|
print("[ground_test] fortress kill +300 ok")
|
|
_score_before = _game.score
|
|
_ship.apply_damage(999)
|
|
_next_phase()
|
|
4:
|
|
if _phase_time >= 0.6:
|
|
if _game.score != _score_before + 800:
|
|
_fail("ship score: %d -> %d (expected +800)" % [_score_before, _game.score])
|
|
else:
|
|
print("[ground_test] ship kill +800 ok")
|
|
_next_phase()
|
|
5:
|
|
match _step:
|
|
0:
|
|
_clear_field()
|
|
_lives_before = _game.lives
|
|
var f3 := EnemyFortress.new()
|
|
f3.setup(_game.player.global_position.x, _game.player.global_position.y, 1.0)
|
|
_game._enemies.add_child(f3)
|
|
_restart_step()
|
|
1:
|
|
if _phase_time >= 0.8:
|
|
if _game.lives != _lives_before or not _game.player.active:
|
|
_fail("ramming fortress hurt player: lives %d->%d active=%s" % [
|
|
_lives_before, _game.lives, str(_game.player.active)])
|
|
else:
|
|
print("[ground_test] player overlaps fortress unharmed ok")
|
|
_next_phase()
|
|
6:
|
|
match _step:
|
|
0:
|
|
_clear_field()
|
|
var f4 := EnemyFortress.new()
|
|
f4.setup(270.0, 300.0, 1.0)
|
|
_game._enemies.add_child(f4)
|
|
var bullet := PlayerBullet.new()
|
|
bullet.direction = Vector2.UP
|
|
(_game.get_node("PlayerBullets") as Node2D).add_child(bullet)
|
|
bullet.position = Vector2(270.0, 430.0)
|
|
_restart_step()
|
|
1:
|
|
if _phase_time >= 0.7:
|
|
if _game._enemies.get_child_count() == 0:
|
|
_fail("fortress missing before bullet-hit check")
|
|
else:
|
|
var target := _game._enemies.get_child(0) as EnemyFortress
|
|
if target.hp != 3:
|
|
_fail("player bullet did not hit fortress: hp=%d expected 3" % target.hp)
|
|
else:
|
|
print("[ground_test] player bullet hits fortress ok")
|
|
return _finish()
|
|
return false
|