AlicizaX/Client/Assets/Scripts/New/Example/App/TimerService.cs
2026-03-25 18:33:59 +08:00

151 lines
3.9 KiB
C#

using System;
using System.Collections.Generic;
namespace Aliciza.Services.Example
{
public sealed class TimerService : ServiceBase, ITimerService, IServiceTickable, IServiceOrder
{
private readonly List<TimerTask> _timers = new List<TimerTask>();
private int _nextTimerId = 1;
public float ElapsedTime { get; private set; }
public int Order => -1000;
public int Once(float delay, Action callback)
{
if (callback == null)
{
throw new ArgumentNullException(nameof(callback));
}
return AddTimer(delay, 0f, 1, callback);
}
public int Repeat(float interval, Action callback, int repeatCount = -1, float firstDelay = -1f)
{
if (callback == null)
{
throw new ArgumentNullException(nameof(callback));
}
if (interval <= 0f)
{
throw new ArgumentOutOfRangeException(nameof(interval), "Repeat interval must be greater than zero.");
}
var delay = firstDelay < 0f ? interval : firstDelay;
return AddTimer(delay, interval, repeatCount, callback);
}
public bool Cancel(int timerId)
{
for (var i = 0; i < _timers.Count; i++)
{
if (_timers[i].Id != timerId)
{
continue;
}
_timers.RemoveAt(i);
return true;
}
return false;
}
public void CancelAll()
{
_timers.Clear();
}
public void Tick(float deltaTime)
{
ElapsedTime += deltaTime;
for (var i = _timers.Count - 1; i >= 0; i--)
{
var timer = _timers[i];
timer.Remaining -= deltaTime;
if (timer.Remaining > 0f)
{
_timers[i] = timer;
continue;
}
timer.Callback?.Invoke();
if (timer.RepeatCount == 1)
{
_timers.RemoveAt(i);
continue;
}
if (timer.RepeatCount > 1)
{
timer.RepeatCount--;
}
if (timer.Interval <= 0f)
{
_timers.RemoveAt(i);
continue;
}
timer.Remaining += timer.Interval;
if (timer.Remaining <= 0f)
{
timer.Remaining = timer.Interval;
}
_timers[i] = timer;
}
}
protected override void OnInitialize()
{
ElapsedTime = 0f;
}
protected override void OnDestroyService()
{
CancelAll();
ElapsedTime = 0f;
}
private int AddTimer(float delay, float interval, int repeatCount, Action callback)
{
if (delay < 0f)
{
throw new ArgumentOutOfRangeException(nameof(delay), "Delay cannot be negative.");
}
if (repeatCount == 0)
{
throw new ArgumentOutOfRangeException(nameof(repeatCount), "Repeat count cannot be zero.");
}
var id = _nextTimerId++;
_timers.Add(new TimerTask
{
Id = id,
Remaining = delay,
Interval = interval,
RepeatCount = repeatCount,
Callback = callback,
});
return id;
}
private struct TimerTask
{
public int Id;
public float Remaining;
public float Interval;
public int RepeatCount;
public Action Callback;
}
}
}