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;
}
}
}