Files
urm03/scripts/spawner.gd
T
vh 380088c694 feat: tracer bullet — greybox arena, positioning piloting, auto-fire KINETIC weapon
One-screen 640x360 arena (walls, grid floor, fixed view), mech with
positioning-only movement (WASD/arrows, accel/decel, no aim), auto-fire
KINETIC hardpoint (nearest-target, visible range ring) firing slugs
that damage + knock back, untagged grunt trickle spawner with contact
damage, hull bar HUD, scene-reload on hull zero.

Headless smoke gate: tests/smoke.tscn asserts boot, piloting movement,
spawning, input-free auto-fire, grunt lethality, knockback displacement.
3/3 passes on nh3-dev headless 4.7.1.
2026-08-06 22:21:10 -07:00

45 lines
1.3 KiB
GDScript

extends Node2D
## Keeps a floor count of grunts alive, spawning at the arena's inset
## edges. Endless trickle — the tracer needs targets, not waves.
signal grunt_spawned(grunt: Node)
const GRUNT := preload("res://scenes/grunt.tscn")
@export var target_count := 8
@export var spawn_interval := 0.8
@export var spawn_rect := Rect2(32, 32, 576, 296)
@export var min_dist_from_mech := 120.0
var _timer := 0.0
func _physics_process(delta: float) -> void:
_timer -= delta
if _timer > 0.0:
return
_timer = spawn_interval
if get_tree().get_nodes_in_group("enemies").size() < target_count:
_spawn()
func _spawn() -> void:
var g := GRUNT.instantiate()
g.position = _pick_point()
add_child(g)
grunt_spawned.emit(g)
func _pick_point() -> Vector2:
var mech := get_tree().get_first_node_in_group("mech") as Node2D
var p := Vector2.ZERO
for i in 12:
match randi() % 4:
0: p = Vector2(randf_range(spawn_rect.position.x, spawn_rect.end.x), spawn_rect.position.y)
1: p = Vector2(randf_range(spawn_rect.position.x, spawn_rect.end.x), spawn_rect.end.y)
2: p = Vector2(spawn_rect.position.x, randf_range(spawn_rect.position.y, spawn_rect.end.y))
3: p = Vector2(spawn_rect.end.x, randf_range(spawn_rect.position.y, spawn_rect.end.y))
if mech == null or p.distance_to(mech.global_position) >= min_dist_from_mech:
return p
return p