Syntriax.Engine/Engine.Systems/Time/TimerBehaviour.cs

118 lines
2.7 KiB
C#

using Syntriax.Engine.Core;
namespace Syntriax.Engine.Systems.Time;
public class TimerBehaviour : Behaviour, IUpdate, ITimer
{
public Event<IReadOnlyTimer> OnStarted { get; } = new();
public Event<IReadOnlyTimer, IReadOnlyTimer.TimerDeltaArguments> OnDelta { get; } = new();
public Event<IReadOnlyTimer> OnStopped { get; } = new();
public Event<IReadOnlyTimer> OnPaused { get; } = new();
public Event<IReadOnlyTimer> OnResumed { get; } = new();
public TimerState State { get; protected set; } = TimerState.Idle;
public double StartTime { get; protected set; } = 0f;
public float Percentage => (float)(1f - (Remaining / StartTime));
private double _remaining = 0f;
public double Remaining
{
get => _remaining;
protected set
{
if (value < .0f)
value = .0f;
_remaining = value;
}
}
private bool shouldBeTicking = false;
private bool hasStartedTickingBefore = false;
public virtual void Start(double time)
{
StartTime = time;
Remaining = time;
shouldBeTicking = true;
hasStartedTickingBefore = false;
if (IsActive)
StartTimer();
}
public virtual void Stop()
{
if (!shouldBeTicking)
return;
shouldBeTicking = false;
State = TimerState.Stopped;
OnStopped?.Invoke(this);
}
public void Update()
{
if (State is not TimerState.Ticking)
return;
double delta = Universe.Time.DeltaSpan.TotalSeconds;
Remaining -= delta;
OnDelta?.Invoke(this, new(delta));
if (Remaining <= .0f)
Stop();
}
protected override void OnEnteredUniverse(IUniverse universe)
{
if (!shouldBeTicking || State is TimerState.Ticking)
return;
if (hasStartedTickingBefore)
Resume();
else
StartTimer();
}
protected override void OnExitedUniverse(IUniverse universe)
{
if (!shouldBeTicking || State is not TimerState.Ticking)
return;
Pause();
}
public virtual void Pause()
{
State = TimerState.Paused;
OnPaused?.Invoke(this);
}
public virtual void Resume()
{
State = TimerState.Ticking;
OnResumed?.Invoke(this);
}
private void StartTimer()
{
hasStartedTickingBefore = true;
State = TimerState.Ticking;
OnStarted?.Invoke(this);
}
protected override void OnFinalize()
{
StartTime = 0f;
Remaining = 0f;
State = TimerState.Idle;
shouldBeTicking = false;
hasStartedTickingBefore = false;
}
}