diff --git a/UnityProject/Assets/Scenes/main.unity b/UnityProject/Assets/Scenes/main.unity index 0f6b994c..601c8aaa 100644 --- a/UnityProject/Assets/Scenes/main.unity +++ b/UnityProject/Assets/Scenes/main.unity @@ -153,7 +153,7 @@ Transform: m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 709048975} - m_RootOrder: 10 + m_RootOrder: 11 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!114 &450845954 MonoBehaviour: @@ -381,7 +381,7 @@ Transform: m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 709048975} - m_RootOrder: 6 + m_RootOrder: 7 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!114 &683825228 MonoBehaviour: @@ -441,6 +441,7 @@ Transform: m_Children: - {fileID: 964133197} - {fileID: 1751957488} + - {fileID: 1029867562} - {fileID: 877336934} - {fileID: 803382966} - {fileID: 790894654} @@ -505,7 +506,7 @@ Transform: m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 709048975} - m_RootOrder: 4 + m_RootOrder: 5 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!114 &790894655 MonoBehaviour: @@ -571,7 +572,7 @@ Transform: m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 709048975} - m_RootOrder: 3 + m_RootOrder: 4 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!114 &803382967 MonoBehaviour: @@ -617,7 +618,7 @@ Transform: m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 709048975} - m_RootOrder: 2 + m_RootOrder: 3 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!114 &877336935 MonoBehaviour: @@ -696,7 +697,7 @@ Transform: m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 709048975} - m_RootOrder: 9 + m_RootOrder: 10 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!114 &914171639 MonoBehaviour: @@ -790,7 +791,7 @@ Transform: m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 709048975} - m_RootOrder: 5 + m_RootOrder: 6 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!114 &965975542 MonoBehaviour: @@ -814,6 +815,50 @@ MonoBehaviour: downloadingMaxNum: 3 failedTryAgain: 3 adaptiveReplacementCacheCapacity: 32 +--- !u!1 &1029867561 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1029867562} + - component: {fileID: 1029867563} + m_Layer: 0 + m_Name: Timer + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1029867562 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1029867561} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 709048975} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &1029867563 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1029867561} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5e79c115d5054209810f42dc6e25cf94, type: 3} + m_Name: + m_EditorClassIdentifier: --- !u!1 &1047779123 GameObject: m_ObjectHideFlags: 0 @@ -844,7 +889,7 @@ Transform: m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 709048975} - m_RootOrder: 11 + m_RootOrder: 12 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!114 &1047779125 MonoBehaviour: @@ -967,7 +1012,7 @@ Transform: m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 709048975} - m_RootOrder: 7 + m_RootOrder: 8 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!114 &1666908678 MonoBehaviour: @@ -1055,7 +1100,7 @@ Transform: m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 709048975} - m_RootOrder: 8 + m_RootOrder: 9 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!114 &1863338242 MonoBehaviour: diff --git a/UnityProject/Assets/TEngine/Runtime/Modules/GameModule.cs b/UnityProject/Assets/TEngine/Runtime/Modules/GameModule.cs index fcba4595..abb96b62 100644 --- a/UnityProject/Assets/TEngine/Runtime/Modules/GameModule.cs +++ b/UnityProject/Assets/TEngine/Runtime/Modules/GameModule.cs @@ -99,6 +99,13 @@ namespace TEngine public static SceneModule Scene => _scene ??= Get(); private static SceneModule _scene; + + /// + /// 获取计时器模块。 + /// + public static TimerModule Timer => _timer ??= Get(); + + private static TimerModule _timer; #endregion /// @@ -153,6 +160,7 @@ namespace TEngine _ui = null; _localization = null; _scene = null; + _timer = null; } } } \ No newline at end of file diff --git a/UnityProject/Assets/TEngine/Runtime/Modules/TimerModule.meta b/UnityProject/Assets/TEngine/Runtime/Modules/TimerModule.meta new file mode 100644 index 00000000..4e8c7993 --- /dev/null +++ b/UnityProject/Assets/TEngine/Runtime/Modules/TimerModule.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: d56be587f7b64f4aac094df08798619f +timeCreated: 1700625097 \ No newline at end of file diff --git a/UnityProject/Assets/TEngine/Runtime/Modules/TimerModule/TimerManager.cs b/UnityProject/Assets/TEngine/Runtime/Modules/TimerModule/TimerManager.cs new file mode 100644 index 00000000..bbfc6da1 --- /dev/null +++ b/UnityProject/Assets/TEngine/Runtime/Modules/TimerModule/TimerManager.cs @@ -0,0 +1,465 @@ +using System; +using System.Collections.Generic; + +namespace TEngine +{ + public delegate void TimerHandler(object[] args); + + [UpdateModule] + internal class TimerManager : ModuleImp + { + [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 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(); + } + } + } + + internal override void Update(float elapseSeconds, float realElapseSeconds) + { + UpdateTimer(elapseSeconds); + UpdateUnscaledTimer(realElapseSeconds); + } + + internal override void Shutdown() + { + RemoveAllTimer(); + DestroySystemTimer(); + } + } +} \ No newline at end of file diff --git a/UnityProject/Assets/TEngine/Runtime/Modules/TimerModule/TimerManager.cs.meta b/UnityProject/Assets/TEngine/Runtime/Modules/TimerModule/TimerManager.cs.meta new file mode 100644 index 00000000..1b7e21a7 --- /dev/null +++ b/UnityProject/Assets/TEngine/Runtime/Modules/TimerModule/TimerManager.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 3a3b960842a44c6fbba975083ba5fa50 +timeCreated: 1700625107 \ No newline at end of file diff --git a/UnityProject/Assets/TEngine/Runtime/Modules/TimerModule/TimerModule.cs b/UnityProject/Assets/TEngine/Runtime/Modules/TimerModule/TimerModule.cs new file mode 100644 index 00000000..846b8b36 --- /dev/null +++ b/UnityProject/Assets/TEngine/Runtime/Modules/TimerModule/TimerModule.cs @@ -0,0 +1,170 @@ +using UnityEngine; + +namespace TEngine +{ + /// + /// 计时器模块。 + /// + [DisallowMultipleComponent] + public sealed partial class TimerModule : Module + { + private TimerManager _timerManager; + + /// + /// 游戏框架组件初始化。 + /// + protected override void Awake() + { + base.Awake(); + + _timerManager = ModuleImpSystem.GetModule(); + if (_timerManager == null) + { + Log.Fatal("TimerMgr is invalid."); + } + } + + /// + /// 添加计时器。 + /// + /// 计时器回调。 + /// 计时器间隔。 + /// 是否循环。 + /// 是否不收时间缩放影响。 + /// 传参。(避免闭包) + /// 计时器Id。 + public int AddTimer(TimerHandler callback, float time, bool isLoop = false, bool isUnscaled = false, params object[] args) + { + if (_timerManager == null) + { + throw new GameFrameworkException("TimerMgr is invalid."); + } + + return _timerManager.AddTimer(callback, time, isLoop, isUnscaled, args); + } + + /// + /// 暂停计时器。 + /// + /// 计时器Id。 + public void Stop(int timerId) + { + if (_timerManager == null) + { + throw new GameFrameworkException("TimerMgr is invalid."); + } + + _timerManager.Stop(timerId); + } + + /// + /// 恢复计时器。 + /// + /// 计时器Id。 + public void Resume(int timerId) + { + if (_timerManager == null) + { + throw new GameFrameworkException("TimerMgr is invalid."); + } + + _timerManager.Resume(timerId); + } + + /// + /// 计时器是否在运行中。 + /// + /// 计时器Id。 + /// 否在运行中。 + public bool IsRunning(int timerId) + { + if (_timerManager == null) + { + throw new GameFrameworkException("TimerMgr is invalid."); + } + + return _timerManager.IsRunning(timerId); + } + + /// + /// 获得计时器剩余时间。 + /// + public float GetLeftTime(int timerId) + { + if (_timerManager == null) + { + throw new GameFrameworkException("TimerMgr is invalid."); + } + + return _timerManager.GetLeftTime(timerId); + } + + /// + /// 重置计时器,恢复到开始状态。 + /// + public void Restart(int timerId) + { + if (_timerManager == null) + { + throw new GameFrameworkException("TimerMgr is invalid."); + } + + _timerManager.Restart(timerId); + } + + /// + /// 重置计时器。 + /// + public void ResetTimer(int timerId, TimerHandler callback, float time, bool isLoop = false, bool isUnscaled = false) + { + if (_timerManager == null) + { + throw new GameFrameworkException("TimerMgr is invalid."); + } + + _timerManager.Reset(timerId,callback,time,isLoop,isUnscaled); + } + + /// + /// 重置计时器。 + /// + public void ResetTimer(int timerId, float time, bool isLoop, bool isUnscaled) + { + if (_timerManager == null) + { + throw new GameFrameworkException("TimerMgr is invalid."); + } + + _timerManager.Reset(timerId, time,isLoop,isUnscaled); + } + + /// + /// 移除计时器。 + /// + /// 计时器Id。 + public void RemoveTimer(int timerId) + { + if (_timerManager == null) + { + Log.Fatal("TimerMgr is invalid."); + throw new GameFrameworkException("TimerMgr is invalid."); + } + + _timerManager.RemoveTimer(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/UnityProject/Assets/TEngine/Runtime/Modules/TimerModule/TimerModule.cs.meta b/UnityProject/Assets/TEngine/Runtime/Modules/TimerModule/TimerModule.cs.meta new file mode 100644 index 00000000..4a2993bc --- /dev/null +++ b/UnityProject/Assets/TEngine/Runtime/Modules/TimerModule/TimerModule.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 5e79c115d5054209810f42dc6e25cf94 +timeCreated: 1700625348 \ No newline at end of file