Files
hello-godot/tests/bullet_traj_test.gd
T

102 lines
3.0 KiB
GDScript

extends SceneTree
## 玩家子弹弹道回归测试(时间驱动):
## L4 齐射后快照所有子弹位置,0.25s 后比对实际位移方向,
## 必须命中 UP / ±22° / ±30° 五个弹道之一,且各组数量正确。
## 在 spawner 首波敌机(0.8s)出现前完成测量,保证确定性。
## 运行:godot --headless -s tests/bullet_traj_test.gd
const SNAP_DELAY := 0.1
const FLY_TIME := 0.25
const DOT_EPS := 0.995
const GLOBAL_TIMEOUT := 15.0
var _time := 0.0
var _snapped := false
var _game: Game
var _pbullets: Node2D
var _fails: Array[String] = []
var _snapshot: Array = [] # [bullet: Node2D, pos: Vector2]
func _initialize() -> void:
_game = (load("res://scenes/game.tscn") as PackedScene).instantiate()
root.add_child(_game)
print("[traj_test] game instantiated")
func _fail(msg: String) -> void:
_fails.append(msg)
print("[FAIL] " + msg)
func _ensure_refs() -> bool:
if _pbullets == null:
_pbullets = _game.get_node_or_null("PlayerBullets") as Node2D
return _pbullets != null
func _process(delta: float) -> bool:
_time += delta
if _time > GLOBAL_TIMEOUT:
_fail("global timeout")
return _finish()
if not _ensure_refs():
return false
if not _snapped and _time >= SNAP_DELAY:
_snapped = true
# 先射一梭子 L4(fire 从首帧按住,此处已有一发齐射在飞)
_game.player.weapon_level = 4
Input.action_release("fire")
_game.player._fire()
_snapshot = []
for bullet in _pbullets.get_children():
_snapshot.append([bullet, (bullet as Node2D).position])
if _snapshot.size() != 12:
_fail("L4 volley=%d expected 12" % _snapshot.size())
return false
if _snapped and _time >= SNAP_DELAY + FLY_TIME:
var allowed := [
Vector2.UP,
Vector2.UP.rotated(deg_to_rad(-22.0)),
Vector2.UP.rotated(deg_to_rad(22.0)),
Vector2.UP.rotated(deg_to_rad(-30.0)),
Vector2.UP.rotated(deg_to_rad(30.0)),
]
var counts := [0, 0, 0, 0, 0]
var classified := 0
for entry in _snapshot:
var bullet: Node2D = entry[0]
var start: Vector2 = entry[1]
if not is_instance_valid(bullet):
_fail("bullet freed before measurement window ended")
continue
var disp: Vector2 = bullet.position - start
if disp.length() < 50.0:
_fail("bullet barely moved: %.1f px" % disp.length())
continue
var dir := disp.normalized()
for i in allowed.size():
if dir.dot(allowed[i]) >= DOT_EPS:
counts[i] += 1
classified += 1
break
if classified != _snapshot.size():
_fail("only %d/%d bullets on valid trajectories" % [classified, _snapshot.size()])
elif counts[0] != 6 or counts[1] != 2 or counts[2] != 2 or counts[3] != 1 or counts[4] != 1:
_fail("trajectory group counts wrong: straight=%d L22=%d R22=%d L30=%d R30=%d" % counts)
else:
print("[traj_test] trajectories ok: straight=%d ±22=%d+%d ±30=%d+%d" % [counts[0], counts[1], counts[2], counts[3], counts[4]])
return _finish()
return false
func _finish() -> bool:
if _fails.is_empty():
print("[traj_test] PASS")
else:
print("[traj_test] FAIL: %d issue(s)" % _fails.size())
quit(0 if _fails.is_empty() else 1)
return true