Files
Syntriax.Engine/Engine.Systems/Time/Timer.cs
Syntriax 988a6f67f2 BREAKING CHANGE: renamed original Behaviour class to BehaviourInternal, and replaced it with BehaviourBase
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.
2025-10-22 16:50:19 +03:00

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