diff --git a/Assets/TEngine/Runtime/GameFramework/Timer.meta b/Assets/TEngine/Runtime/GameFramework/Timer.meta new file mode 100644 index 00000000..82a8c33e --- /dev/null +++ b/Assets/TEngine/Runtime/GameFramework/Timer.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 555d657d6bb444a983750fb61876af89 +timeCreated: 1681822247 \ No newline at end of file diff --git a/Assets/TEngine/Runtime/GameFramework/Timer/Timer.meta b/Assets/TEngine/Runtime/GameFramework/Timer/Timer.meta new file mode 100644 index 00000000..1ec86396 --- /dev/null +++ b/Assets/TEngine/Runtime/GameFramework/Timer/Timer.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 9d644fbcf0a6413da6f4d0c54724266a +timeCreated: 1681822257 \ No newline at end of file diff --git a/Assets/TEngine/Runtime/GameFramework/Timer/Timer/TimerManager.cs b/Assets/TEngine/Runtime/GameFramework/Timer/Timer/TimerManager.cs new file mode 100644 index 00000000..083c7318 --- /dev/null +++ b/Assets/TEngine/Runtime/GameFramework/Timer/Timer/TimerManager.cs @@ -0,0 +1,465 @@ +using System; +using System.Collections.Generic; + +namespace TEngine +{ + public delegate void TimerHandler(object[] args); + + internal class TimerManager : GameFrameworkModule + { + [Serializable] + public 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(); + + /// + /// 添加计时器 + /// + /// + /// + /// + /// + /// + /// + 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); + } + } + } + + /// + /// 暂停计时 + /// + public void Stop(int timerId) + { + Timer timer = GetTimer(timerId); + if (timer != null) timer.isRunning = false; + } + + /// + /// 恢复计时 + /// + public void Resume(int timerId) + { + Timer timer = GetTimer(timerId); + if (timer != null) timer.isRunning = true; + } + + /// + /// 计时器是否在运行中 + /// + 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 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; + } + } + } + + /// + /// 移除计时器 + /// + /// + 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(); + } + + /// + /// 根据TimerId获取计时器 + /// + /// + /// + 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(); + } + } + } + + internal override void Update(float elapseSeconds, float realElapseSeconds) + { + UpdateTimer(elapseSeconds); + UpdateUnscaledTimer(realElapseSeconds); + } + + internal override void Shutdown() + { + DestroySystemTimer(); + } + } +} \ No newline at end of file diff --git a/Assets/TEngine/Runtime/GameFramework/Timer/Timer/TimerModule.cs b/Assets/TEngine/Runtime/GameFramework/Timer/Timer/TimerModule.cs new file mode 100644 index 00000000..fa27dcc4 --- /dev/null +++ b/Assets/TEngine/Runtime/GameFramework/Timer/Timer/TimerModule.cs @@ -0,0 +1,115 @@ +using UnityEngine; + +namespace TEngine +{ + /// + /// 计时器模块。 + /// + [DisallowMultipleComponent] + public sealed partial class TimerModule : GameFrameworkModuleBase + { + private TimerManager _timerManager; + + /// + /// 游戏框架组件初始化。 + /// + protected override void Awake() + { + base.Awake(); + + _timerManager = GameFrameworkEntry.GetModule(); + if (_timerManager == null) + { + Log.Fatal("TimerMgr is invalid."); + } + } + + /// + /// 添加计时器 + /// + /// + /// + /// + /// + /// + /// + public int AddTimer(TimerHandler callback, float time, bool isLoop = false, bool isUnscaled = false, params object[] args) + { + if (_timerManager == null) + { + Log.Fatal("TimerMgr is invalid."); + throw new GameFrameworkException("TimerMgr is invalid."); + } + + return _timerManager.AddTimer(callback, time, isLoop, isUnscaled, args); + } + + /// + /// 暂停计时 + /// + public void Stop(int timerId) + { + if (_timerManager == null) + { + Log.Fatal("TimerMgr is invalid."); + throw new GameFrameworkException("TimerMgr is invalid."); + } + _timerManager.Stop(timerId); + } + + /// + /// 移除计时器 + /// + /// + public void RemoveTimer(int timerId) + { + if (_timerManager == null) + { + Log.Fatal("TimerMgr is invalid."); + throw new GameFrameworkException("TimerMgr is invalid."); + } + _timerManager.RemoveTimer(timerId); + } + + /// + /// 恢复计时 + /// + public void Resume(int timerId) + { + if (_timerManager == null) + { + Log.Fatal("TimerMgr is invalid."); + throw new GameFrameworkException("TimerMgr is invalid."); + } + _timerManager.Resume(timerId); + } + + /// + /// 计时器是否在运行中 + /// + public bool IsRunning(int timerId) + { + if (_timerManager == null) + { + Log.Fatal("TimerMgr is invalid."); + throw new GameFrameworkException("TimerMgr is invalid."); + } + + return _timerManager.IsRunning(timerId); + } + + /// + /// 移除所有计时器 + /// + public void RemoveAllTimer() + { + if (_timerManager == null) + { + Log.Fatal("TimerMgr is invalid."); + throw new GameFrameworkException("TimerMgr is invalid."); + } + + _timerManager.RemoveAllTimer(); + } + } +} \ No newline at end of file diff --git a/Assets/TEngine/Runtime/GameModule.cs b/Assets/TEngine/Runtime/GameModule.cs index ea8e591b..c2e2fa88 100644 --- a/Assets/TEngine/Runtime/GameModule.cs +++ b/Assets/TEngine/Runtime/GameModule.cs @@ -53,6 +53,11 @@ public class GameModule:MonoBehaviour /// 获取音频模块。 /// public static AudioModule Audio { get; private set; } + + /// + /// 计时器模块。 + /// + public static TimerModule Timer { get; private set; } #endregion @@ -70,6 +75,7 @@ public class GameModule:MonoBehaviour Setting = Get(); UI = Get(); Audio = Get(); + Timer = Get(); } private static void InitCustomModules()