Development Merge 2025.04.01 #1

Merged
Syntriax merged 32 commits from development into main 2025-04-01 19:20:18 +03:00
10 changed files with 346 additions and 0 deletions
Showing only changes of commit 7a1dd7eb1a - Show all commits

View File

@ -0,0 +1,18 @@
namespace Syntriax.Engine.Systems.Time;
public interface IReadOnlyStopwatch
{
event StopwatchEventHandler? OnStarted;
event StopwatchDeltaEventHandler? OnDelta;
event StopwatchEventHandler? OnStopped;
double Time { get; }
TimerState State { get; }
event StopwatchEventHandler? OnPaused;
event StopwatchEventHandler? OnResumed;
delegate void StopwatchEventHandler(IReadOnlyStopwatch sender);
delegate void StopwatchDeltaEventHandler(IReadOnlyStopwatch sender, double delta);
}

View File

@ -0,0 +1,11 @@
namespace Syntriax.Engine.Systems.Time;
public interface IReadOnlyTicker : IReadOnlyStopwatch
{
event TickerTickEventHandler? OnTick;
int TickCounter { get; }
double TickPeriod { get; set; }
delegate void TickerTickEventHandler(IReadOnlyTicker sender);
}

View File

@ -0,0 +1,22 @@
namespace Syntriax.Engine.Systems.Time;
public interface IReadOnlyTimer
{
event TimerEventHandler? OnStarted;
event TimerDeltaEventHandler? OnDelta;
event TimerEventHandler? OnStopped;
event TimerEventHandler? OnPaused;
event TimerEventHandler? OnResumed;
double StartTime { get; }
double Remaining { get; }
float Percentage { get; }
TimerState State { get; }
delegate void TimerEventHandler(IReadOnlyTimer sender);
delegate void TimerDeltaEventHandler(IReadOnlyTimer sender, double delta);
}

View File

@ -0,0 +1,10 @@
namespace Syntriax.Engine.Systems.Time;
public interface IStopwatch : IReadOnlyStopwatch
{
void StopwatchStart();
void StopwatchStop();
void StopwatchPause();
void StopwatchResume();
}

View File

@ -0,0 +1,11 @@
namespace Syntriax.Engine.Systems.Time;
public interface ITicker : IStopwatch
{
event TickerTickEventHandler? OnTick;
int TickCounter { get; }
double TickPeriod { get; set; }
delegate void TickerTickEventHandler(ITicker sender);
}

View File

@ -0,0 +1,10 @@
namespace Syntriax.Engine.Systems.Time;
public interface ITimer : IReadOnlyTimer
{
void TimerStart(double time);
void TimerStop();
void TimerPause();
void TimerResume();
}

View File

@ -0,0 +1,99 @@
using Syntriax.Engine.Core;
using Syntriax.Engine.Core.Abstract;
namespace Syntriax.Engine.Systems.Time;
public class StopwatchBehaviour : Behaviour, IStopwatch
{
public event IReadOnlyStopwatch.StopwatchEventHandler? OnStarted = null;
public event IReadOnlyStopwatch.StopwatchDeltaEventHandler? OnDelta = null;
public event IReadOnlyStopwatch.StopwatchEventHandler? OnStopped = null;
public event IReadOnlyStopwatch.StopwatchEventHandler? OnPaused = null;
public event IReadOnlyStopwatch.StopwatchEventHandler? OnResumed = null;
public double Time { get; protected set; } = 0f;
public TimerState State { get; protected set; } = TimerState.Idle;
private bool shouldBeTicking = false;
private bool hasStartedTickingBefore = false;
public virtual void StopwatchStart()
{
Time = 0f;
shouldBeTicking = true;
hasStartedTickingBefore = false;
if (IsActive)
StartStopwatch();
}
public virtual void StopwatchStop()
{
if (!shouldBeTicking)
return;
shouldBeTicking = false;
State = TimerState.Stopped;
OnStopped?.Invoke(this);
}
protected override void OnUpdate()
{
if (State is not TimerState.Ticking)
return;
double delta = GameManager.Time.DeltaSpan.TotalSeconds;
Time += delta;
OnDelta?.Invoke(this, delta);
}
protected override void OnEnteredHierarchy(IGameManager gameManager)
{
if (!shouldBeTicking || State is TimerState.Ticking)
return;
if (hasStartedTickingBefore)
StopwatchResume();
else
StartStopwatch();
}
protected override void OnExitedHierarchy(IGameManager gameManager)
{
if (!shouldBeTicking || State is not TimerState.Ticking)
return;
StopwatchPause();
}
public virtual void StopwatchPause()
{
State = TimerState.Paused;
OnPaused?.Invoke(this);
}
public virtual void StopwatchResume()
{
State = TimerState.Ticking;
OnResumed?.Invoke(this);
}
private void StartStopwatch()
{
hasStartedTickingBefore = true;
State = TimerState.Ticking;
OnStarted?.Invoke(this);
}
protected override void OnFinalize()
{
Time = 0f;
State = TimerState.Idle;
shouldBeTicking = false;
hasStartedTickingBefore = false;
}
}

View File

@ -0,0 +1,38 @@
namespace Syntriax.Engine.Systems.Time;
public class TickerBehaviour : StopwatchBehaviour, ITicker
{
public event ITicker.TickerTickEventHandler? OnTick = null;
public double TickPeriod { get; set; } = 1f;
public int TickCounter { get; private set; } = 0;
private double nextTick = 0f;
public override void StopwatchStart()
{
TickCounter = 0;
base.StopwatchStart();
nextTick = Time + TickPeriod;
}
protected override void OnUpdate()
{
base.OnUpdate();
if (Time < nextTick)
return;
nextTick += TickPeriod;
TickCounter++;
OnTick?.Invoke(this);
}
protected override void OnFinalize()
{
base.OnFinalize();
TickCounter = 0;
nextTick = 0f;
}
}

View File

@ -0,0 +1,118 @@
using Syntriax.Engine.Core;
using Syntriax.Engine.Core.Abstract;
namespace Syntriax.Engine.Systems.Time;
public class TimerBehaviour : Behaviour, ITimer
{
public event IReadOnlyTimer.TimerEventHandler? OnStarted = null;
public event IReadOnlyTimer.TimerDeltaEventHandler? OnDelta = null;
public event IReadOnlyTimer.TimerEventHandler? OnStopped = null;
public event IReadOnlyTimer.TimerEventHandler? OnPaused = null;
public event IReadOnlyTimer.TimerEventHandler? OnResumed = null;
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 TimerStart(double time)
{
StartTime = time;
Remaining = time;
shouldBeTicking = true;
hasStartedTickingBefore = false;
if (IsActive)
StartTimer();
}
public virtual void TimerStop()
{
if (!shouldBeTicking)
return;
shouldBeTicking = false;
State = TimerState.Stopped;
OnStopped?.Invoke(this);
}
protected override void OnUpdate()
{
if (State is not TimerState.Ticking)
return;
double delta = GameManager.Time.DeltaSpan.TotalSeconds;
Remaining -= delta;
OnDelta?.Invoke(this, delta);
if (Remaining <= .0f)
TimerStop();
}
protected override void OnEnteredHierarchy(IGameManager gameManager)
{
if (!shouldBeTicking || State is TimerState.Ticking)
return;
if (hasStartedTickingBefore)
TimerResume();
else
StartTimer();
}
protected override void OnExitedHierarchy(IGameManager gameManager)
{
if (!shouldBeTicking || State is not TimerState.Ticking)
return;
TimerPause();
}
public virtual void TimerPause()
{
State = TimerState.Paused;
OnPaused?.Invoke(this);
}
public virtual void TimerResume()
{
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;
}
}

View File

@ -0,0 +1,9 @@
namespace Syntriax.Engine.Systems.Time;
public enum TimerState
{
Idle,
Ticking,
Paused,
Stopped
}