138 lines
4.8 KiB
C#
138 lines
4.8 KiB
C#
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<LaserBeam> allLasers = new List<LaserBeam>();
|
|
|
|
private readonly List<List<LaserBeam>> batches = new();
|
|
private readonly List<LaserBeam> activeLasers = new();
|
|
|
|
void Start()
|
|
{
|
|
// Use active-only; if you need inactive too, use FindObjectsOfType<LaserBeam>(true)
|
|
allLasers.AddRange(FindObjectsOfType<LaserBeam>());
|
|
|
|
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()
|
|
{
|
|
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)
|
|
{
|
|
// Compute runway required to complete a Charge->Fire sequence
|
|
float runway = Mathf.Max(0f, chargingWindup) + Mathf.Max(0f, fireDuration);
|
|
float timeLeft = batchEnd - Time.time;
|
|
|
|
// If not enough time to do Charging+Firing, just stay Idle until the batch ends.
|
|
if (timeLeft < runway)
|
|
{
|
|
yield return PhaseBlock(LaserPhase.Idle, timeLeft, batchEnd);
|
|
break;
|
|
}
|
|
|
|
// IDLE
|
|
float idleTime = Mathf.Max(0f, idleBeforeCharge);
|
|
// If idleTime itself would consume too much and leave < runway, trim idle to fit
|
|
if (idleTime > 0f && idleTime > timeLeft - runway)
|
|
idleTime = Mathf.Max(0f, timeLeft - runway);
|
|
|
|
if (idleTime > 0f)
|
|
{
|
|
yield return PhaseBlock(LaserPhase.Idle, idleTime, batchEnd);
|
|
if (Time.time >= batchEnd) break;
|
|
}
|
|
|
|
// CHARGING (blink)
|
|
if (chargingWindup > 0f)
|
|
{
|
|
yield return PhaseBlock(LaserPhase.Charging, chargingWindup, batchEnd);
|
|
// we guaranteed runway, so we should still have time left for Firing
|
|
}
|
|
|
|
// FIRING (lethal)
|
|
if (fireDuration > 0f)
|
|
{
|
|
yield return PhaseBlock(LaserPhase.Firing, fireDuration, batchEnd);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// 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);
|
|
}
|
|
}
|