facsimile-wing/scripts/power_up_spawner.gd

126 lines
4.1 KiB
GDScript

class_name PowerUpSpawner extends Node2D
@export var spawn_interval: float = 5.0
@export var test_mode: bool = true
# PackedScene for the pickup template — configure in the scene editor.
@export var pickup_scene: PackedScene
@onready var screensize: Vector2 = get_viewport().content_scale_size
@onready var spawn_timer: Timer = $SpawnTimer
# All weapon resources to spawn as pickups.
# Populate in the editor with your weapon_shot resources.
@export var all_weapon_shots: Array[WeaponShot] = []
var _pickups_spawned: int = 0
var _pickups_remaining: int = 0
func _ready() -> void:
if spawn_timer == null:
return
spawn_timer.wait_time = spawn_interval
func _on_spawn_timer_timeout() -> void:
if test_mode:
_spawn_test_pickups()
else:
_spawn_normal_pickup()
func _spawn_normal_pickup() -> void:
# Spawn a single random pickup at a position near the player.
if all_weapon_shots.is_empty():
return
var pickup := _spawn_pickup(
all_weapon_shots[randi() % all_weapon_shots.size()]
)
if pickup == null or not is_instance_valid(pickup):
return
# Position: centered horizontally, above the player with vertical padding.
var player_node := get_node_or_null("../Player")
if player_node != null:
pickup.position = Vector2(
randf_range(40.0, screensize.x - 40.0),
player_node.position.y - randf_range(80.0, 200.0)
)
else:
pickup.position = Vector2(
randf_range(40.0, screensize.x - 40.0),
randf_range(30.0, screensize.y * 0.4)
)
add_child(pickup)
_pickups_spawned += 1
_pickups_remaining = max(_pickups_remaining, _pickups_spawned)
func _spawn_test_pickups() -> void:
for weapon: WeaponShot in all_weapon_shots:
if weapon == null or weapon.shot_name.is_empty():
continue
var pickup := _spawn_pickup(weapon)
if not is_instance_valid(pickup):
continue # skipped — no valid icon
# Random position within viewport, with edge padding.
var margin: float = 15.0
pickup.position = Vector2(
randf_range(margin, screensize.x - margin),
randf_range(margin, screensize.y - margin)
)
add_child(pickup)
_pickups_spawned += 1
_pickups_remaining = _pickups_spawned
# Pause the timer while pickups are on screen; resume when all gone.
if spawn_timer != null:
spawn_timer.stop()
func pickup_collected() -> void:
# Called by the player when a pickup is collected.
# Sync WeaponComponent's test_mode so tab cycling stays independent of
# pickups when in test mode, and normal behavior is restored otherwise.
var level: Node2D = get_parent() as Node2D
if level != null:
var wc: WeaponComponent = level.get_node_or_null("WeaponComponent")
if wc != null:
wc.test_mode = test_mode
# Decrement counter; resume timer once all pickups are gone.
_pickups_remaining = max(0, _pickups_remaining - 1)
if _pickups_remaining <= 0:
if spawn_timer != null:
spawn_timer.start()
_pickups_spawned = 0
func _spawn_pickup(weapon: WeaponShot) -> Area2D:
# Validate that the weapon has a pickup icon configured.
if weapon.pickup_icon == null:
printerr("[PowerUpSpawner] No pickup icon set for weapon: ", weapon.shot_name)
var dead := Area2D.new() # return a dead node — caller skips it
dead.queue_free()
return dead
# Instantiate the scene template and attach weapon metadata.
var pickup := pickup_scene.instantiate() as Area2D
if pickup == null:
printerr("[PowerUpSpawner] Failed to instantiate pickup scene.")
return null
pickup.set_meta("weapon_shot", weapon)
# Add the icon node at runtime (scene has no TextureRect to avoid null-dependency issues).
var icon := TextureRect.new()
icon.texture = weapon.pickup_icon
icon.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED
icon.size = Vector2(16, 16)
pickup.add_child(icon)
return pickup