Unity 从零开始的框架搭建 1-8 封装一个依赖于MonoBehaviour的计时器(上) 基本功能_unity 计时器框架
灵感来自下面这本书的协程部分,因此我就自己尝试写了一个
我的新书Unity3D游戏开发(第3版) | 雨松MOMO程序研究院
如果你不知道什么是协程:unity保姆级教程之协同程序_unity协同-CSDN博客
一句话概括:协程就是单线程的异步操作,其作用于Unity的主线程
1.我写了如下几个功能(只展示无参数):
基础校验
private bool CheckCount(int count) { if (count < 0) { Debug.LogError(\"循环次数不能为负数!\"); return false; } return true; } private bool CheckTime(float time) { if (time < 0) { Debug.LogError(\"等待时间不能为负数!\"); return false; } return true; }
1.等待受缩放时间影响后的秒数
public void WaitTime(float waitTime, Action callback) { if (CheckTime(waitTime)) { StartCoroutine(WaitTimeHandle(waitTime, () => callback?.Invoke())); } }
2.等待不受缩放时间影响后的秒数
public void WaitRealTime(float waitTime, Action callback) { if (CheckTime(waitTime)) { StartCoroutine(WaitRealTimeHandle(waitTime, () => callback?.Invoke())); } }
2.按固定时间间隔循环执行
public void LoopTime(float spacing, int overNumber, Action callback) { if (CheckTime(spacing) && CheckCount(overNumber)) { StartCoroutine(LoopTimeHandle(spacing, overNumber, () => callback?.Invoke())); } }
3.等待固定帧执行一次
public void WaitFrame(int frameCount, Action callback) { if (CheckCount(frameCount)) { StartCoroutine(WaitFrameHandle(frameCount, () => callback?.Invoke())); } }
4.进度反馈
public void WaitTimeWithProgress(float waitTime, Action progressCallback, Action completeCallback) { if (CheckTime(waitTime)) { StartCoroutine(ProgressTimer(waitTime, progressCallback, completeCallback)); } } private IEnumerator ProgressTimer(float duration, Action progress, Action complete) { float startTime = Time.time; while (Time.time - startTime < duration) { progress?.Invoke((Time.time - startTime) / duration); yield return null; } complete?.Invoke(); }
5.等待当前帧渲染结束执行回调(本帧执行)
public void WaitForEndOfFrame(Action callback) { StartCoroutine(WaitForEndOfFrameHandle(callback)); } private IEnumerator WaitForEndOfFrameHandle(Action callback) { yield return new WaitForEndOfFrame(); callback?.Invoke(); }
2.总览
回调函数我写了无参 一参 两参的版本 可以自行添加参数
using System;using System.Collections;using UnityEngine;public class TimeManager : MonoBehaviour{ private static TimeManager instance; public static TimeManager Instance => instance; private void Awake() { if (instance == null) { instance = this; } } private bool CheckCount(int count) { if (count < 0) { Debug.LogError(\"循环次数不能为负数!\"); return false; } return true; } private bool CheckTime(float time) { if (time < 0) { Debug.LogError(\"等待时间不能为负数!\"); return false; } return true; } #region 等待固定时间秒 /// /// 等待固定时间以后执行回调 /// /// 等待时间(秒) /// 回调函数 public void WaitTime(float waitTime, Action callback) { if (CheckTime(waitTime)) { StartCoroutine(WaitTimeHandle(waitTime, () => callback?.Invoke())); } } public void WaitTime(float waitTime, T param, Action callback) { if (CheckTime(waitTime)) { StartCoroutine(WaitTimeHandle(waitTime, () => callback?.Invoke(param))); } } public void WaitTime(float waitTime, T param1, K param2, Action callback) { if (CheckTime(waitTime)) { StartCoroutine(WaitTimeHandle(waitTime, () => callback?.Invoke(param1, param2))); } } private IEnumerator WaitTimeHandle(float waitTime, Action action) { yield return new WaitForSeconds(waitTime); action?.Invoke(); } #endregion #region 等待固定时间秒(不受缩放影响) /// /// 等待固定时间以后执行回调(不受Time.timeScale影响) /// /// 等待时间(秒) /// 回调函数 public void WaitRealTime(float waitTime, Action callback) { if (CheckTime(waitTime)) { StartCoroutine(WaitRealTimeHandle(waitTime, () => callback?.Invoke())); } } public void WaitRealTime(float waitTime, T param, Action callback) { if (CheckTime(waitTime)) { StartCoroutine(WaitRealTimeHandle(waitTime, () => callback?.Invoke(param))); } } public void WaitRealTime(float waitTime, T param1, K param2, Action callback) { if (CheckTime(waitTime)) { StartCoroutine(WaitRealTimeHandle(waitTime, () => callback?.Invoke(param1, param2))); } } private IEnumerator WaitRealTimeHandle(float waitTime, Action action) { yield return new WaitForSecondsRealtime(waitTime); action?.Invoke(); } #endregion #region 按固定时间间隔循环执行 public void LoopTime(float spacing, int overNumber, Action callback) { if (CheckTime(spacing) && CheckCount(overNumber)) { StartCoroutine(LoopTimeHandle(spacing, overNumber, () => callback?.Invoke())); } } public void LoopTime(float spacing, int overNumber, T param, Action callback) { if (CheckTime(spacing) && CheckCount(overNumber)) { StartCoroutine(LoopTimeHandle(spacing, overNumber, () => callback?.Invoke(param))); } } public void LoopTime(float spacing, int overNumber, T param1, K param2, Action callback) { if (CheckTime(spacing) && CheckCount(overNumber)) { StartCoroutine(LoopTimeHandle(spacing, overNumber, () => callback?.Invoke(param1, param2))); } } private IEnumerator LoopTimeHandle(float spacing, int overNumber, Action action) { for (int i = 0; i callback?.Invoke())); } } public void WaitFrame(int frameCount, T param, Action callback) { if (CheckCount(frameCount)) { StartCoroutine(WaitFrameHandle(frameCount, () => callback?.Invoke(param))); } } public void WaitFrame(int frameCount, T param1, K param2, Action callback) { if (CheckCount(frameCount)) { StartCoroutine(WaitFrameHandle(frameCount, () => callback?.Invoke(param1, param2))); } } private IEnumerator WaitFrameHandle(int frameCount, Action action) { for (int i = 0; i < frameCount; i++) { yield return null; } action?.Invoke(); } #endregion #region 进度反馈 public void WaitTimeWithProgress(float waitTime, Action progressCallback, Action completeCallback) { if (CheckTime(waitTime)) { StartCoroutine(ProgressTimer(waitTime, progressCallback, completeCallback)); } } private IEnumerator ProgressTimer(float duration, Action progress, Action complete) { float startTime = Time.time; while (Time.time - startTime < duration) { progress?.Invoke((Time.time - startTime) / duration); yield return null; } complete?.Invoke(); } public void WaitTimeWithProgress(float waitTime, T param, Action progressCallback, Action completeCallback) { if (CheckTime(waitTime)) { StartCoroutine(ProgressTimer(waitTime, param, progressCallback, completeCallback)); } } private IEnumerator ProgressTimer(float duration, T param, Action progress, Action complete) { float startTime = Time.time; while (Time.time - startTime < duration) { progress?.Invoke((Time.time - startTime) / duration, param); yield return null; } complete?.Invoke(param); } public void WaitTimeWithProgress(float waitTime, T param1, K param2, Action progressCallback, Action completeCallback) { if (CheckTime(waitTime)) { StartCoroutine(ProgressTimer(waitTime, param1, param2, progressCallback, completeCallback)); } } private IEnumerator ProgressTimer(float duration, T param1, K param2, Action progress, Action complete) { float startTime = Time.time; while (Time.time - startTime < duration) { progress?.Invoke((Time.time - startTime) / duration, param1, param2); yield return null; } complete?.Invoke(param1, param2); } #endregion #region 等待当前帧结束执行回调 public void WaitForEndOfFrame(Action callback) { StartCoroutine(WaitForEndOfFrameHandle(callback)); } private IEnumerator WaitForEndOfFrameHandle(Action callback) { yield return new WaitForEndOfFrame(); callback?.Invoke(); } public void WaitForEndOfFrame(T param, Action callback) { StartCoroutine(WaitForEndOfFrameHandle(param, callback)); } private IEnumerator WaitForEndOfFrameHandle(T param, Action callback) { yield return new WaitForEndOfFrame(); callback?.Invoke(param); } public void WaitForEndOfFrame(T param1, K param2, Action callback) { StartCoroutine(WaitForEndOfFrameHandle(param1, param2, callback)); } private IEnumerator WaitForEndOfFrameHandle(T param1, K param2, Action callback) { yield return new WaitForEndOfFrame(); callback?.Invoke(param1, param2); } #endregion public void Stop(IEnumerator func) { StopCoroutine(func); } public void StopAll() { StopAllCoroutines(); } public TimeChainContext StartChain() { return new TimeChainContext(this); }}
3.Ai给出了如下拓展思路
优先级高
链式调用扩展
物理时间步长同步
优先级中
调试可视化工具
网络同步时钟
优先级低
自动化测试框架集成
使用Mono管理类去管理该脚本从而摆脱Mono的控制
我目前的需求没有这么复杂,当作一个简单的计时器使用
其是依赖于Unity的这一点可以用await和async来替代,但是可能涉及到了多线程,我这块学了但是用的不多还需加强