using System.Collections; using System.Collections.Generic; using UnityEngine; using static LaserBeam; public class LaserBeamController : MonoBehaviour { [Header("Cycle Durations")] public float interval = 20f; // how long each batch runs before switching public float idleBeforeCharge = 3f; // Idle time before Charging public float chargingWindup = 1f; // Charging duration (blink) public float fireDuration = 1f; // Firing duration (lethal) [Header("Beams (auto-populated)")] public List allLasers = new List(); private readonly List> batches = new(); private readonly List activeLasers = new(); void Start() { // Use active-only; if you need inactive too, use FindObjectsOfType(true) allLasers.AddRange(FindObjectsOfType()); foreach (var lb in allLasers) { if (!lb) continue; lb.externalControl = true; // controller owns timing lb.ResetCycle(); // Idle + line off lb.enabled = false; // completely inert until selected } // Shuffle for (int i = 0; i < allLasers.Count; i++) { int r = Random.Range(i, allLasers.Count); (allLasers[i], allLasers[r]) = (allLasers[r], allLasers[i]); } // Split into 3 batches int batchSize = Mathf.CeilToInt(Mathf.Max(1, allLasers.Count) / 3f); for (int i = 0; i < allLasers.Count; i += batchSize) batches.Add(allLasers.GetRange(i, Mathf.Min(batchSize, allLasers.Count - i))); StartCoroutine(RunBatches()); } IEnumerator RunBatches() { while (true) // <— keep cycling batches forever { for (int bi = 0; bi < batches.Count; bi++) { // Disable everything first foreach (var lb in allLasers) if (lb) { lb.enabled = false; lb.ResetCycle(); } // Activate this batch activeLasers.Clear(); activeLasers.AddRange(batches[bi]); foreach (var l in activeLasers) { if (!l) continue; l.enabled = true; l.ResetCycle(); l.SetLaserPhase(LaserPhase.Idle); } float batchEnd = Time.time + interval; // Loop phases for the duration of this batch while (Time.time < batchEnd) { float runway = Mathf.Max(0f, chargingWindup) + Mathf.Max(0f, fireDuration); float timeLeft = batchEnd - Time.time; if (timeLeft < runway) { // Stay idle until batch end yield return PhaseBlock(LaserPhase.Idle, timeLeft, batchEnd); break; } // IDLE float idleTime = Mathf.Max(0f, idleBeforeCharge); if (idleTime > timeLeft - runway) idleTime = Mathf.Max(0f, timeLeft - runway); if (idleTime > 0f) { yield return PhaseBlock(LaserPhase.Idle, idleTime, batchEnd); if (Time.time >= batchEnd) break; } if (chargingWindup > 0f) yield return PhaseBlock(LaserPhase.Charging, chargingWindup, batchEnd); if (fireDuration > 0f) yield return PhaseBlock(LaserPhase.Firing, fireDuration, batchEnd); } // After each batch, force a clean Idle/off so nothing stays lit SetPhaseForAll(LaserPhase.Idle); } } } // Set phase for all active lasers and tick per-frame for 'duration' (clamped by batch end) IEnumerator PhaseBlock(LaserPhase phase, float duration, float batchHardEnd) { SetPhaseForAll(phase); float end = Mathf.Min(Time.time + duration, batchHardEnd); while (Time.time < end) { if (phase == LaserPhase.Charging) { foreach (var l in activeLasers) if (l && l.isActiveAndEnabled) l.TickLaserDuringCharging(); } else if (phase == LaserPhase.Firing) { foreach (var l in activeLasers) if (l && l.isActiveAndEnabled) l.TickLaserDuringFiring(); } yield return null; } } void SetPhaseForAll(LaserPhase p) { foreach (var l in activeLasers) if (l && l.isActiveAndEnabled) l.SetLaserPhase(p); } }