计时器封装

发布时间 2023-06-13 18:15:22作者: 狐狸爱看书

 心血来潮写个计时器玩一下

在开发的过程中难免会遇到需要大量的计时器,有一个好的计时器对开发或者程序的运行效率都有很大的提升

作为一个合格的程序员,我们不可能每次有计时都在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 = TimerConManager.Instance.StartTimeDown(waitTime, () =>
         {
             if (this != null)
             {
                 action();
             }
             RemoveAction(action);
         }, loopNum);
        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();
    }
}