using System; using System.Collections.Generic; namespace TEngine { public delegate void TimerHandler(object[] args); internal class TimerModule : Module, IUpdateModule, ITimerModule { [Serializable] internal class Timer { public int timerId = 0; public float curTime = 0; public float time = 0; public TimerHandler Handler; public bool isLoop = false; public bool isNeedRemove = false; public bool isRunning = false; public bool isUnscaled = false; //是否使用非缩放的时间 public object[] Args = null; //回调参数 } private int _curTimerId = 0; private readonly List _timerList = new List(); private readonly List _unscaledTimerList = new List(); private readonly List _cacheRemoveTimers = new List(); private readonly List _cacheRemoveUnscaledTimers = new List(); /// /// 添加计时器。 /// /// 计时器回调。 /// 计时器间隔。 /// 是否循环。 /// 是否不收时间缩放影响。 /// 传参。(避免闭包) /// 计时器Id。 public int AddTimer(TimerHandler callback, float time, bool isLoop = false, bool isUnscaled = false, params object[] args) { Timer timer = new Timer { timerId = ++_curTimerId, curTime = time, time = time, Handler = callback, isLoop = isLoop, isUnscaled = isUnscaled, Args = args, isNeedRemove = false, isRunning = true }; InsertTimer(timer); return timer.timerId; } private void InsertTimer(Timer timer) { bool isInsert = false; if (timer.isUnscaled) { for (int i = 0, len = _unscaledTimerList.Count; i < len; i++) { if (_unscaledTimerList[i].curTime > timer.curTime) { _unscaledTimerList.Insert(i, timer); isInsert = true; break; } } if (!isInsert) { _unscaledTimerList.Add(timer); } } else { for (int i = 0, len = _timerList.Count; i < len; i++) { if (_timerList[i].curTime > timer.curTime) { _timerList.Insert(i, timer); isInsert = true; break; } } if (!isInsert) { _timerList.Add(timer); } } } /// /// 暂停计时器。 /// /// 计时器Id。 public void Stop(int timerId) { Timer timer = GetTimer(timerId); if (timer != null) timer.isRunning = false; } /// /// 恢复计时器。 /// /// 计时器Id。 public void Resume(int timerId) { Timer timer = GetTimer(timerId); if (timer != null) timer.isRunning = true; } /// /// 计时器是否在运行中。 /// /// 计时器Id。 /// 否在运行中。 public bool IsRunning(int timerId) { Timer timer = GetTimer(timerId); return timer is { isRunning: true }; } /// /// 获得计时器剩余时间 /// public float GetLeftTime(int timerId) { Timer timer = GetTimer(timerId); if (timer == null) return 0; return timer.curTime; } /// /// 重置计时器,恢复到开始状态。 /// public void Restart(int timerId) { Timer timer = GetTimer(timerId); if (timer != null) { timer.curTime = timer.time; timer.isRunning = true; } } public void ResetTimer(int timerId, TimerHandler callback, float time, bool isLoop = false, bool isUnscaled = false) { Reset(timerId, callback, time, isLoop, isUnscaled); } public void ResetTimer(int timerId, float time, bool isLoop, bool isUnscaled) { Reset(timerId, time, isLoop, isUnscaled); } /// /// 重置计时器。 /// public void Reset(int timerId, TimerHandler callback, float time, bool isLoop = false, bool isUnscaled = false) { Timer timer = GetTimer(timerId); if (timer != null) { timer.curTime = time; timer.time = time; timer.Handler = callback; timer.isLoop = isLoop; timer.isNeedRemove = false; if (timer.isUnscaled != isUnscaled) { RemoveTimerImmediate(timerId); timer.isUnscaled = isUnscaled; InsertTimer(timer); } } } /// /// 重置计时器。 /// public void Reset(int timerId, float time, bool isLoop, bool isUnscaled) { Timer timer = GetTimer(timerId); if (timer != null) { timer.curTime = time; timer.time = time; timer.isLoop = isLoop; timer.isNeedRemove = false; if (timer.isUnscaled != isUnscaled) { RemoveTimerImmediate(timerId); timer.isUnscaled = isUnscaled; InsertTimer(timer); } } } /// /// 立即移除。 /// /// private void RemoveTimerImmediate(int timerId) { for (int i = 0, len = _timerList.Count; i < len; i++) { if (_timerList[i].timerId == timerId) { _timerList.RemoveAt(i); return; } } for (int i = 0, len = _unscaledTimerList.Count; i < len; i++) { if (_unscaledTimerList[i].timerId == timerId) { _unscaledTimerList.RemoveAt(i); return; } } } /// /// 移除计时器。 /// /// 计时器Id。 public void RemoveTimer(int timerId) { for (int i = 0, len = _timerList.Count; i < len; i++) { if (_timerList[i].timerId == timerId) { _timerList[i].isNeedRemove = true; return; } } for (int i = 0, len = _unscaledTimerList.Count; i < len; i++) { if (_unscaledTimerList[i].timerId == timerId) { _unscaledTimerList[i].isNeedRemove = true; return; } } } /// /// 移除所有计时器。 /// public void RemoveAllTimer() { _timerList.Clear(); _unscaledTimerList.Clear(); } private Timer GetTimer(int timerId) { for (int i = 0, len = _timerList.Count; i < len; i++) { if (_timerList[i].timerId == timerId) { return _timerList[i]; } } for (int i = 0, len = _unscaledTimerList.Count; i < len; i++) { if (_unscaledTimerList[i].timerId == timerId) { return _unscaledTimerList[i]; } } return null; } private void LoopCallInBadFrame() { bool isLoopCall = false; for (int i = 0, len = _timerList.Count; i < len; i++) { Timer timer = _timerList[i]; if (timer.isLoop && timer.curTime <= 0) { if (timer.Handler != null) { timer.Handler(timer.Args); } timer.curTime += timer.time; if (timer.curTime <= 0) { isLoopCall = true; } } } if (isLoopCall) { LoopCallInBadFrame(); } } private void LoopCallUnscaledInBadFrame() { bool isLoopCall = false; for (int i = 0, len = _unscaledTimerList.Count; i < len; i++) { Timer timer = _unscaledTimerList[i]; if (timer.isLoop && timer.curTime <= 0) { if (timer.Handler != null) { timer.Handler(timer.Args); } timer.curTime += timer.time; if (timer.curTime <= 0) { isLoopCall = true; } } } if (isLoopCall) { LoopCallUnscaledInBadFrame(); } } private void UpdateTimer(float elapseSeconds) { bool isLoopCall = false; for (int i = 0, len = _timerList.Count; i < len; i++) { Timer timer = _timerList[i]; if (timer.isNeedRemove) { _cacheRemoveTimers.Add(i); continue; } if (!timer.isRunning) continue; timer.curTime -= elapseSeconds; if (timer.curTime <= 0) { if (timer.Handler != null) { timer.Handler(timer.Args); } if (timer.isLoop) { timer.curTime += timer.time; if (timer.curTime <= 0) { isLoopCall = true; } } else { _cacheRemoveTimers.Add(i); } } } for (int i = _cacheRemoveTimers.Count - 1; i >= 0; i--) { _timerList.RemoveAt(_cacheRemoveTimers[i]); _cacheRemoveTimers.RemoveAt(i); } if (isLoopCall) { LoopCallInBadFrame(); } } private void UpdateUnscaledTimer(float realElapseSeconds) { bool isLoopCall = false; for (int i = 0, len = _unscaledTimerList.Count; i < len; i++) { Timer timer = _unscaledTimerList[i]; if (timer.isNeedRemove) { _cacheRemoveUnscaledTimers.Add(i); continue; } if (!timer.isRunning) continue; timer.curTime -= realElapseSeconds; if (timer.curTime <= 0) { if (timer.Handler != null) { timer.Handler(timer.Args); } if (timer.isLoop) { timer.curTime += timer.time; if (timer.curTime <= 0) { isLoopCall = true; } } else { _cacheRemoveUnscaledTimers.Add(i); } } } for (int i = _cacheRemoveUnscaledTimers.Count - 1; i >= 0; i--) { _unscaledTimerList.RemoveAt(_cacheRemoveUnscaledTimers[i]); _cacheRemoveUnscaledTimers.RemoveAt(i); } if (isLoopCall) { LoopCallUnscaledInBadFrame(); } } private readonly List _ticker = new List(); public System.Timers.Timer AddSystemTimer(Action callBack) { int interval = 1000; var timerTick = new System.Timers.Timer(interval); timerTick.AutoReset = true; timerTick.Enabled = true; timerTick.Elapsed += new System.Timers.ElapsedEventHandler(callBack); _ticker.Add(timerTick); return timerTick; } private void DestroySystemTimer() { foreach (var ticker in _ticker) { if (ticker != null) { ticker.Stop(); } } } public override void OnInit() { } public override void Shutdown() { RemoveAllTimer(); DestroySystemTimer(); } public void Update(float elapseSeconds, float realElapseSeconds) { UpdateTimer(elapseSeconds); UpdateUnscaledTimer(realElapseSeconds); } } }