前言:好久没写博客了,倒不是没写的了, 现在手里堆着的demo和小功能很多,而是懒,我是真滴懒啊。
需求:1.延迟执行方法;2.循环执行,间隔可控制;3.可以改变更新模式(update、fixedupdate,lateupdate),可以决定是否会受到Unity时间缩放影响;4.调用简单,可复用
思路:
1.改变更新模式和受到unity时间缩放的功能,可以使用全局静态变量控制
2.目前网上做定时器的方法三种:Coroutine、update、invoke,我选的第二种,使用MonoBehavior的update来做更新
3.不搞什么单例Manager之类的,调用麻烦,写的一长串,什么Instance的,看着很low
4.Timer对象只对数据信息做保存之用,更新时间状态等,集中由一个脚本的Update处理,分割数据层和逻辑层
5.虽然大部分使用Timer都是随用随丢,不会暂存,但是我new对象时,仍要保留这个功能,而且还要重置、完成等功能
实现:
第一步就是先实现UpdateRegister功能,继承自MonoBehavior,使用Unity自己的Update方法。提供给外部注册和取消注册的功能
using System.Collections; using System.Collections.Generic; using UnityEngine; using System; namespace JunFramework { public enum UpdateMode { Update, FixedUpdate, LateUpdate } public enum TimeMode { Scaled, UnScaled } public class UpdateRegister : MonoBehaviour { /// <summary> /// update注册列表 /// </summary> private static Dictionary<int, Action> update = new Dictionary<int, Action>(); /// <summary> /// fixedupfate注册列表 /// </summary> private static Dictionary<int, Action> fixedupdate = new Dictionary<int, Action>(); /// <summary> /// lateupdate注册列表 /// </summary> private static Dictionary<int, Action> lateupdate = new Dictionary<int, Action>(); /// <summary> /// 全局唯一update下标 /// </summary> private static int updateIndex = 0; /// <summary> /// 是否初始化 /// </summary> private static bool isInit = false; /// <summary> /// 是否已经初始化 /// </summary> public static bool IsInit { get => isInit; } /// <summary> /// 注册 /// </summary> /// <param name="mode"></param> /// <param name="handler"></param> /// <returns></returns> public static int Register(UpdateMode mode, Action handler) { ++updateIndex; switch (mode) { case UpdateMode.Update: update.Add(updateIndex, handler); break; case UpdateMode.FixedUpdate: fixedupdate.Add(updateIndex, handler); break; case UpdateMode.LateUpdate: lateupdate.Add(updateIndex, handler); break; } return updateIndex; } /// <summary> /// 根据updateindex取消注册 /// </summary> /// <param name="mode"></param> /// <param name="index"></param> public static void Cancle(UpdateMode mode, int index) { switch (mode) { case UpdateMode.Update: update.Remove(index); break; case UpdateMode.FixedUpdate: fixedupdate.Remove(index); break; case UpdateMode.LateUpdate: lateupdate.Remove(index); break; } } private void Awake() { isInit = true; } private void Update() { using (var e = update.GetEnumerator()) { if (e.MoveNext()) { e.Current.Value?.Invoke(); } } } private void FixedUpdate() { using (var e = fixedupdate.GetEnumerator()) { if (e.MoveNext()) { e.Current.Value?.Invoke(); } } } private void LateUpdate() { using (var e = lateupdate.GetEnumerator()) { if (e.MoveNext()) { e.Current.Value?.Invoke(); } } } } }
第二步实现Timer对象,存储调用者传入的信息,可获取Timer状态(是否完成?是否正在工作?当前进度?)。可调用开始、结束、暂停、继续、重置、完成功能
using System.Collections; using System.Collections.Generic; using UnityEngine; using System; namespace JunFramework.Timer { public class Timer { #region timer设置 /// <summary> /// Timer是否自动释放 /// </summary> public static bool IsAutoRelease = true; /// <summary> /// Timer更新模式 /// </summary> public static UpdateMode TimerUpdateMode = UpdateMode.FixedUpdate; /// <summary> /// Timer时间是否收到Unity缩放影响 /// </summary> public static TimeMode TimerScaledModel = TimeMode.UnScaled; #endregion private float currentTime = 0f;//当前时间(0 -- steptime) private int currentRepeat = 0;//当前重复次数 private float stepTime = 0f;//间隔 private int repeatTimes = 0;//重复次数 private bool isLoop = false;//是否循环 private bool isDone = false;//是否完成 private bool isStart = false;//是否开始 private int updateIndex = 0;//update注册获取的下标,用于移除update注册 private Action callback;//回调 private float timeAcceleration;//每帧增加的时间 /// <summary> /// 是否完成 /// </summary> public bool IsDone { get => isDone; } /// <summary> /// 当前进度 /// </summary> public float Progress { get => currentTime / stepTime; } /// <summary> /// 是否正在工作 /// </summary> public bool IsWokring { get => !isDone && isStart; } /// <summary> /// /// </summary> /// <param name="stepTime">间隔时长</param> /// <param name="repeatTimes">重复次数</param> /// <param name="callback">回调</param> public Timer(float stepTime, int repeatTimes, Action callback) { this.currentTime = 0f; this.currentRepeat = 0; this.stepTime = stepTime; this.repeatTimes = repeatTimes; this.isLoop = false; this.isDone = false; this.timeAcceleration = GetPerTime(); this.callback = callback; } /// <summary> /// /// </summary> /// <param name="stepTime">间隔</param> /// <param name="callback">回调</param> public Timer(float stepTime, Action callback) { this.currentTime = 0f; this.currentRepeat = 0; this.stepTime = stepTime; this.repeatTimes = 1; this.isLoop = false; this.isDone = false; this.timeAcceleration = GetPerTime(); this.callback = callback; } /// <summary> /// /// </summary> /// <param name="stepTime">间隔</param> /// <param name="isLoop">是否循环</param> /// <param name="callback">回调</param> public Timer(float stepTime, bool isLoop, Action callback) { this.currentTime = 0f; this.currentRepeat = 0; this.stepTime = stepTime; this.isLoop = isLoop; if (!isLoop) { this.repeatTimes = 1; } this.timeAcceleration = GetPerTime(); this.isDone = false; this.callback = callback; } /// <summary> /// 每帧更新 /// </summary> /// <param name="addTime">每帧增加的时间</param> private void Update(float addTime) { if (isDone) return; if (!isStart) return; currentTime += addTime; if (currentTime >= stepTime) { callback?.Invoke(); currentTime = 0f; if (!isLoop) { ++currentRepeat; if (currentRepeat >= repeatTimes) { isDone = true; if (IsAutoRelease) { Stop(); } } } } } /// <summary> /// 开始计时器 /// </summary> public void Start() { if (!UpdateRegister.IsInit) { Debug.LogWarning("UpdateRegister is not init, so this action will not works, please init UpdateRegister first!!!"); return; } isStart = true; this.updateIndex = UpdateRegister.Register(TimerUpdateMode, () => this.Update(timeAcceleration)); } /// <summary> /// 停止计时器(如果只是想暂停可用Pause,stop操作不可恢复) /// </summary> public void Stop() { isStart = false; isDone = true; UpdateRegister.Cancle(TimerUpdateMode, this.updateIndex); } /// <summary> /// 暂停 /// </summary> public void Pause() { isStart = false; } /// <summary> /// 继续 /// </summary> public void Resume() { isStart = true; } /// <summary> /// 重置 /// </summary> public void Reset() { isStart = false; isDone = false; currentTime = 0f; currentRepeat = 0; } /// <summary> /// 不用等待,直接完成 /// </summary> public void Complete() { if (isLoop) return; isDone = true; int tempRepeat = repeatTimes; while (tempRepeat > 0) { callback?.Invoke(); --tempRepeat; } Stop(); } /// <summary> /// 通过更新模式和time模式获取每帧更新时间 /// </summary> /// <returns></returns> private float GetPerTime() { float resultTime = 0f; if (TimerScaledModel == TimeMode.Scaled && TimerUpdateMode == UpdateMode.FixedUpdate) { resultTime = Time.fixedDeltaTime; } else if (TimerScaledModel == TimeMode.UnScaled && TimerUpdateMode == UpdateMode.FixedUpdate) { resultTime = Time.fixedUnscaledDeltaTime; } else if (TimerScaledModel == TimeMode.Scaled && TimerUpdateMode == UpdateMode.Update) { resultTime = Time.deltaTime; } else if (TimerScaledModel == TimeMode.UnScaled && TimerUpdateMode == UpdateMode.FixedUpdate) { resultTime = Time.unscaledDeltaTime; } return resultTime; } } }
第三步,简单编写测试代码
using System.Collections; using System.Collections.Generic; using UnityEngine; using JunFramework.Timer; public class TimerExample : MonoBehaviour { private Timer timer = null; // Start is called before the first frame update void Start() { Timer.IsAutoRelease = true; Timer.TimerScaledModel = JunFramework.TimeMode.UnScaled; Timer.TimerUpdateMode = JunFramework.UpdateMode.FixedUpdate; //Example1 //int i = 0; //Timer timer = new Timer(2, 2, () => Debug.Log(i++)); //timer.Start(); //Example2 //timer = new Timer(2, true, () => Debug.Log("执行")); //timer.Start(); //Example3 timer = new Timer(2, 3, () => Debug.Log("看我看我")); timer.Start(); timer.Complete(); timer.Reset(); timer.Start(); } // Update is called once per frame void Update() { //Example2 //if (Input.GetKeyDown(KeyCode.Space)) //{ // timer.Pause(); //} //else if (Input.GetKeyDown(KeyCode.A)) //{ // timer.Resume(); //} } }
总结:
本次Timer参考的是公司的lua Timer,其实这Timer也是大神蒙占志写的。我这个是C#写的,用于自己的游戏Demo。接受各种改进建议
标签:UpdateMode,定时器,void,private,Unity,Timer,using,public From: https://www.cnblogs.com/JunJiang-Blog/p/16948170.html