Original Behaviour was using old methods for detecting entering/exiting universe, they are now all under the same hood and the original is kept for UniverseEntranceManager because it needs to enter the universe without itself. The internal behaviour kept under a subnamespace of "Core.Internal" for the purpose that it might come in handy for other use cases.
120 lines
2.7 KiB
C#
120 lines
2.7 KiB
C#
using Engine.Core;
|
|
|
|
namespace Engine.Systems.Time;
|
|
|
|
public class Timer : Behaviour, IUpdate, IEnterUniverse, IExitUniverse, 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 virtual 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();
|
|
}
|
|
|
|
public void EnterUniverse(IUniverse universe)
|
|
{
|
|
if (!shouldBeTicking || State is TimerState.Ticking)
|
|
return;
|
|
|
|
if (hasStartedTickingBefore)
|
|
Resume();
|
|
else
|
|
StartTimer();
|
|
}
|
|
|
|
public void ExitUniverse(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 FinalizeInternal()
|
|
{
|
|
base.FinalizeInternal();
|
|
|
|
StartTime = 0f;
|
|
Remaining = 0f;
|
|
State = TimerState.Idle;
|
|
shouldBeTicking = false;
|
|
hasStartedTickingBefore = false;
|
|
}
|
|
}
|