using System.Collections.Generic; using Godot; using GodotHostTest.Helpers; using GodotHostTest.Interfaces; using OwofGames.AetherBind; using R3; namespace GodotHostTest.Game.Target; public partial class TargetSpawner : Node2D, ITargetCollector, ITargetSpawner { private readonly List _availableTargets = []; private readonly Subject _targetSpawned = new(); [Export] public required Timer Timer; [Inject] private ILevel _level = null!; [Inject] private ITargetEventBus _targetEventBus = null!; /// public void NewTarget(ITarget target) { // record the target as available _availableTargets.Add(target); // whenever the target gets disabled, mark it as available again target.Hit.Merge(target.TimedOut) .Select(_ => target) .Subscribe(_availableTargets.Add) .AddTo(this); } public Observable TargetSpawned => _targetSpawned.AsObservable(); public override void _Ready() { // inform the target event bus that there's a new target spawner _targetEventBus.NewTargetSpawner(this); // spawn every total seconds (and immediately spawn something at ready) Timer.Start(_level.TimeBetweenSpawns.TotalSeconds); Spawn(); } private void OnTimer() { Spawn(); } private void Spawn() { // pick a random target var randomIndex = GD.RandRange(0, _availableTargets.Count - 1); var target = _availableTargets[randomIndex]; _availableTargets.RemoveAt(randomIndex); // enable it target.Enable(); // notify that a target has been spawned _targetSpawned.OnNext(target); } protected override void Dispose(bool disposing) { base.Dispose(disposing); _targetSpawned.Dispose(); } }