77 lines
2.1 KiB
GDScript
77 lines
2.1 KiB
GDScript
extends Node3D
|
|
|
|
signal matador_killed
|
|
signal all_defeated
|
|
|
|
const MATADOR := preload("res://Matador.tscn")
|
|
|
|
var _alive: int = 0
|
|
var _wave: int = 0
|
|
var _resolved: bool = false
|
|
var _spawn_points: Array[Node3D] = []
|
|
|
|
|
|
func _ready() -> void:
|
|
add_to_group(&"matador_spawn")
|
|
_spawn.call_deferred()
|
|
|
|
|
|
# Each spawner node is a spawn-point marker. The first in tree order (the one the HUD
|
|
# connects its all_defeated to) runs the wave logic and uses every marker — itself and
|
|
# its siblings — as an entry point; the rest stay passive so waves aren't run four times.
|
|
func _spawn() -> void:
|
|
var markers := get_tree().get_nodes_in_group(&"matador_spawn")
|
|
if markers.is_empty() or markers[0] != self:
|
|
return
|
|
for node: Node in markers:
|
|
if node is Node3D:
|
|
_spawn_points.append(node as Node3D)
|
|
_place_bull(randf() * TAU, DP.f("arena_spawn_radius"))
|
|
_start_next_wave()
|
|
|
|
|
|
# Wave 1 sends 1 matador, wave 2 sends 2, … up to the number of placed spawn points.
|
|
# Matadors are assigned to a random subset of spawn points each wave and enter staggered.
|
|
func _start_next_wave() -> void:
|
|
_wave += 1
|
|
var count := mini(_wave, _spawn_points.size())
|
|
var points: Array = _spawn_points.duplicate()
|
|
points.shuffle()
|
|
for i: int in count:
|
|
var sp := points[i] as Node3D
|
|
var m := _spawn_at(sp.global_position)
|
|
m.call_deferred(&"enter_spawn_roll", Vector3.ZERO)
|
|
if i < count - 1:
|
|
await get_tree().create_timer(DP.f("mat_spawn_stagger")).timeout
|
|
|
|
|
|
func _place_bull(angle: float, arena_r: float) -> void:
|
|
var bull := get_tree().get_first_node_in_group(&"player") as Node3D
|
|
if not bull:
|
|
return
|
|
bull.global_position = Vector3(
|
|
cos(angle) * arena_r, bull.global_position.y, sin(angle) * arena_r
|
|
)
|
|
|
|
|
|
func _spawn_at(pos: Vector3) -> Node3D:
|
|
var m: Node3D = MATADOR.instantiate()
|
|
m.position = pos
|
|
get_parent().add_child(m)
|
|
m.killed.connect(_on_matador_killed)
|
|
_alive += 1
|
|
return m
|
|
|
|
|
|
func _on_matador_killed() -> void:
|
|
matador_killed.emit()
|
|
_alive -= 1
|
|
if _alive > 0 or _resolved:
|
|
return
|
|
if _wave >= _spawn_points.size():
|
|
_resolved = true
|
|
all_defeated.emit()
|
|
else:
|
|
await get_tree().create_timer(DP.f("mat_wave_pause")).timeout
|
|
_start_next_wave()
|