基于Unity实现的时间计时器系统(较简单)

这次做了个适合新手看的时间计时器系统,实现起来相对简单,总共两个脚本,其中只有一个是核心脚本。

using System;
using System.Collections.Generic;
using UnityEngine;

public class TimeActionNode
{
    /// <summary>
    /// 时间标识
    /// </summary>
    public int guid;
    /// <summary>
    /// 下次要触发的时间
    /// </summary>
    public float needTriggerTime;

    /// <summary>
    /// 注册的时间
    /// </summary>
    public float recordTime;

    /// <summary>
    /// 剩余的触发次数
    /// </summary>
    public int repeatCount;

    /// <summary>
    /// 是否无限次触发
    /// </summary>
    public bool isLoop;

    /// <summary>
    /// 延迟的时间
    /// </summary>
    public float duration;

    /// <summary>
    /// 被清理掉时如果时间未走完 是否会在被清理时触发一次
    /// </summary>
    public bool isInvokeWhenClear;

    /// <summary>
    /// 要执行的事件
    /// </summary>
    public Action action;
}

public class TimeManager
{
    private List<TimeActionNode> totalNodes = new();

    private int originGuid=1000;

    private float nowTime;

    /// <summary>
    /// 
    /// </summary>
    /// <param name="action"></param>
    /// <param name="duration"></param>
    /// <param name="repeatCount">为-1时无限次触发</param>
    /// <param name="isInvokeWhenClear"></param>
    /// <returns></returns>
    public int AddTimeCallBack(Action action, float duration, int repeatCount, bool isInvokeWhenClear)
    {
        TimeActionNode node = ObjectPool.Instance.GetObj<TimeActionNode>();
        node.guid = originGuid++;
        node.recordTime = nowTime;
        node.action = action;
        node.repeatCount = repeatCount;
        node.isLoop = repeatCount == -1;
        node.duration = duration;
        node.needTriggerTime = nowTime + duration;
        node.isInvokeWhenClear = isInvokeWhenClear;
        totalNodes.Add(node);

        return node.guid;
    }

    /// <summary>
    /// 清除某时间事件节点
    /// </summary>
    /// <param name="guid"></param>
    public void ClearGuid(int guid)
    {
        if (totalNodes == null) return;
        for (int i = totalNodes.Count - 1; i >= 0; i--)
        {
            if (guid == totalNodes[i].guid)
            {
                if (totalNodes[i].isInvokeWhenClear)
                    totalNodes[i].action?.Invoke();
                ObjectPool.Instance.StoreObj(totalNodes[i]);
                totalNodes.RemoveAt(i);
                return;
            }
        }
    }
    public void Update()
    {
        nowTime += Time.deltaTime;
        for (int i = totalNodes.Count - 1; i >= 0; i--)
        {
            var node = totalNodes[i];
            //没到时间 下一个
            if (node.needTriggerTime > nowTime) continue;
            //到时间了 执行一次 更新数据
            if (node.repeatCount > 0 || node.isLoop)
            {
                node.action?.Invoke();
                node.repeatCount--;
                if (node.repeatCount <= 0&&!node.isLoop)
                {
                    //触发回收 清除该时间节点
                    ObjectPool.Instance.StoreObj(node);
                    totalNodes.RemoveAt(i);
                }
                //还有触发次数 再次更新数据
                else
                {
                    node.needTriggerTime += node.duration;
                }
            }
        }
    }
}
using System;

public static class TimeSystem
{
    private static TimeManager timeManager = new TimeManager();
    /// <summary>
    /// 添加时间事件
    /// </summary>
    /// <param name="action"></param>
    /// <param name="duration">延迟时间</param>
    /// <param name="repeatCount">为-1时无限次触发</param>
    /// <param name="isInvokeWhenClear">被清除时如果时间没走完的话 是否立刻触发一次</param>
    /// <returns></returns>
    public static int AddTimeCallBack(Action action, float duration, int repeatCount = 1, bool isInvokeWhenClear = false)
    {
        return timeManager.AddTimeCallBack(action, duration, repeatCount, isInvokeWhenClear);
    }

    /// <summary>
    /// 清除某个时间事件节点
    /// </summary>
    /// <param name="guid"></param>
    public static void ClearGuid(int guid)
    {
        timeManager.ClearGuid(guid);
    }

    /// <summary>
    /// 主逻辑中调用 或配合MonoSystem调用
    /// </summary>
    public static void Update()
    {
        timeManager.Update();
    }
}

其中有个ObjectPool对象池,它是同来回收class类对象的,可以不用它,自己new一个新的TimeActionNode也行,用了对象池可以节约一些性能减少GC。

示例如下:

using Sirenix.OdinInspector;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class GameLogic:MonoBehaviour
{
    private int timeId;
    private void Awake()
    {
        MonoSystem.Instance.AddListener(MonoUpdateType.Update,TimeSystem.Update);
    }

    [Button]
    void TestTime()
    {
        timeId=TimeSystem.AddTimeCallBack(() => { Debug.Log("1second later"); },2f,1,true);
        Debug.Log(timeId+"该任务开启计时");
    }

    [Button]
    void testClear()
    {
        TimeSystem.ClearGuid(timeId);
        Debug.Log("清除时间节点事件:"+timeId);
    }
}

在以上代码中的MonoSystem是公共Mono系统,我们可以不用这个系统,只需要在Update函数里调用TimeSystem.Update()函数即可;

结果如下所示:

  • 11
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值