using System.Collections; using System.Collections.Generic; using UnityEngine; namespace RR.Common.Controls { /// /// Строитель последовательности световых эффектов. /// Создаётся через . /// /// SetLight(LightMode.VerticalWave, 3f).Then(LightMode.DiagonalWave, 1.5f).Loop(); /// SetLight(LightMode.VerticalWave, 3f).Then(LightMode.Off); /// SetLight(LightMode.Rainbow, 2f); /// /// public class LightSequence { private readonly struct Step { public readonly LightMode Mode; public readonly float Cycles; public Step(LightMode mode, float cycles) { Mode = mode; Cycles = cycles; } } private readonly List _steps = new(); private readonly LightController _controller; private bool _looping; private Coroutine _coroutine; private int _currentStepIndex; private bool _paused; internal LightSequence(LightController controller, LightMode firstMode, float firstCycles) { _controller = controller; _steps.Add(new Step(firstMode, firstCycles)); } /// Добавляет следующий эффект с количеством циклов по умолчанию. public LightSequence Then(LightMode mode) => Then(mode, _controller.DefaultCycles); /// Добавляет следующий эффект с указанным количеством циклов. public LightSequence Then(LightMode mode, float cycles) { _steps.Add(new Step(mode, cycles)); return this; } /// /// Зацикливает последовательность. Для остановки — . /// public LightSequence Loop() { _looping = true; Play(); return this; } /// Запускает последовательность один раз. public LightSequence Play() { Stop(); _currentStepIndex = 0; _paused = false; _coroutine = _controller.StartCoroutine(RunSequence()); return this; } /// Останавливает выполнение последовательности. public void Stop() { if (_coroutine == null) return; _controller.StopCoroutine(_coroutine); _coroutine = null; _paused = false; } /// /// Приостанавливает последовательность с сохранением текущей позиции. /// public void Pause() { if (_coroutine == null) return; _controller.StopCoroutine(_coroutine); _coroutine = null; _paused = true; } /// /// Возобновляет приостановленную последовательность с сохранённой позиции. /// public void Resume() { if (!_paused) return; _paused = false; _coroutine = _controller.StartCoroutine(RunSequence()); } /// Возвращает true, если последовательность сейчас выполняется. public bool IsPlaying => _coroutine != null; /// Возвращает true, если последовательность приостановлена. public bool IsPaused => _paused; // ReSharper disable once IteratorNeverReturns — цикл намеренно бесконечный при _looping=true private IEnumerator RunSequence() { do { for (int i = _currentStepIndex; i < _steps.Count; i++) { _currentStepIndex = i; Step step = _steps[i]; int commandSeconds = LightCycleDurations.CyclesToCommandSeconds(step.Mode, step.Cycles); _controller.SendCommand(step.Mode, commandSeconds); float waitSeconds = LightCycleDurations.GetCycleSeconds(step.Mode) * step.Cycles; if (step.Mode != LightMode.Off && waitSeconds > 0f) yield return new WaitForSecondsRealtime(waitSeconds); } _currentStepIndex = 0; } while (_looping); _coroutine = null; } } }