计时器封装
心血来潮写个计时器玩一下
在开发的过程中难免会遇到需要大量的计时器,有一个好的计时器对开发或者程序的运行效率都有很大的提升
作为一个合格的程序员,我们不可能每次有计时都在update去做一个计时或者新开一个协程去计时,太麻烦辣,效率太慢辣,性能还差
所以赶紧封装器来...
这个计时器的思路是对需要计时的任务全部存起来,并按照时间的排序插入到一个时间顺序对应的节点,那么只需要有一个计时就可以把所有计时任务统一处理掉
因为插入移除的修改比较频繁,所有用了链表去对各个任务节点做的一个连接
真正在项目里使用的时候还是需要根据实际使用情况来封装的
生命在于成长,如果我的思路有问题可以提出来,谢谢,但不接受喷子,嘿嘿
using System; using System.Collections; using System.Collections.Generic; using UnityEngine; //计时节点 public class TimerCon { public float _waitTime; public float waitTime; // 等待时间 public Action action; // 执行事件 public int loopNum; // 循环次数 0 不循环 -1无限循环 >1指定次数 } public class TimerConManager : UnitySlingleton<TimerConManager> //单例类 处理 { private float timer = 0f; // 当前计时器时间 累计时长 可扩展重置 private bool isActive = true; // 是否激活计时器 LinkedList<TimerCon> nodeList = new LinkedList<TimerCon>(); //节点链表 排序存储计时事件 private Coroutine coroutine; //协程任务 /// <summary> /// 开始计时 外部调用 /// </summary> public void StartTimeDown(float waitTime, Action action, int loopNum = 0) { TimerCon node = new TimerCon(); node._waitTime = waitTime; node.waitTime = waitTime + timer; node.action = action; node.loopNum = loopNum; InsterNode(node); if (coroutine == null) { coroutine = StartCoroutine(Runtime()); } } /// <summary> /// 关闭计时 外部调用 /// </summary> public void RemoveNode(TimerCon node) { if (nodeList.Find(node) != null) { nodeList.Remove(node); } } //插入计时节点 private void InsterNode(TimerCon node) { bool isFirstNodeTimeDown = false; //首节点 if (nodeList.Count == 0) { nodeList.AddLast(node); } else { LinkedListNode<TimerCon> previousNode = GetNodePoint(node.waitTime); isFirstNodeTimeDown = previousNode == nodeList.First; if (isFirstNodeTimeDown) { nodeList.AddBefore(previousNode, node); } else { nodeList.AddAfter(previousNode, node); } } } //计算节点位置 private LinkedListNode<TimerCon> GetNodePoint(float waitTime, LinkedListNode<TimerCon> curNode = null) { if (nodeList.Count == 0) { return null; } if (curNode == null) { curNode = nodeList.First; } //首节点 需特殊处理 if (waitTime <= curNode.Value.waitTime) { return curNode; } if (curNode.Next != null && curNode.Next.Value.waitTime <= waitTime) { return GetNodePoint(waitTime, curNode.Next); } return curNode; } //一直在计时的协程 暂定 private IEnumerator Runtime() { while (isActive) { yield return 0; timer += Time.deltaTime; if (nodeList.Count != 0 && timer >= nodeList.First.Value.waitTime) { DoNode(); } } yield return null; } //运行节点时间 private void DoNode(LinkedListNode<TimerCon> curNode = null) { if (curNode == null) { curNode = nodeList.First; } if (curNode == null) { return; } if (timer >= curNode.Value.waitTime) { curNode.Value.action(); if (curNode.Value.loopNum == -1 || curNode.Value.loopNum > 1) { curNode.Value.loopNum = curNode.Value.loopNum == -1 ? -1 : curNode.Value.loopNum - 1; StartTimeDown(curNode.Value._waitTime, curNode.Value.action, curNode.Value.loopNum); } nodeList.Remove(curNode); curNode = nodeList.First == null ? null : nodeList.First; if (curNode != null && timer >= curNode.Value.waitTime) { DoNode(curNode); } } } }
所谓实际使用的封装
具体情况具体处理辣,肯定不能百分百的通用,是吧,嗯,我觉得是这样的
using System; using System.Collections; using System.Collections.Generic; /// <summary> /// 实体类使用时构造一个TimeConEntity使用 /// 非实体类 可直接使用TimerConManager /// </summary> public class TimeConEntity { private List<Action> timerActions = new List<Action>(); //单个类里面管理计时事件 销毁的时候需要统一清理 /// <summary> /// 开始计时 /// </summary> /// <param name="waitTime">等待时间</param> /// <param name="action">事件</param> /// <param name="loopNum">循环次数 -1为无限循环</param> /// <returns></returns> public Action StartTimer(float waitTime, Action action, int loopNum = 0) {
Action act = () => { }; act = TimerConManager.Instance.StartTimeDown(waitTime, () => { if (this != null) { action(); } RemoveAction(act); }, loopNum);
timerActions.Add(act); return act; } /// <summary> /// 暂停计时 /// </summary> /// <param name="action">计时返回的事件</param> public void StopTimer(Action action) { TimerConManager.Instance.StopTimeDown(action); RemoveAction(action); } /// <summary> /// 清理自身管理数据 /// </summary> /// <param name="action">计时返回的事件</param> private void RemoveAction(Action action) { if (timerActions.Contains(action) == true) { timerActions.Remove(action); } } /// <summary> /// 清理全部计时 销毁时调用 /// </summary> public void Clear() { for (int i = 0; i < timerActions.Count; i++) { StopTimer(timerActions[i]); } timerActions.Clear(); } }
单例类继承模块 这个随意了~
public class UnitySlingleton<T> : MonoBehaviour where T : Component { private static T _instance = null; public static T Instance { get { if (_instance==null) { _instance = FindObjectOfType(typeof(T)) as T; if (_instance==null) { GameObject obj = new GameObject(); obj.hideFlags = HideFlags.DontSave; obj.name = typeof(T).Name; obj.AddComponent<T>(); } } return _instance; } } public virtual void Awake() { DontDestroyOnLoad(this.gameObject); if (_instance == null) { _instance = this as T; } else { GameObject.Destroy(this.gameObject); } } }