Unity定时(延迟)管理器实现

前言

Unity中实现定时功能的方法有很多,比如协程、UpdateInvokeAsync等,可以说是五花八门,对于这类实现方法多、需求频繁的功能还是需要一个管理器来统一处理。

功能

下面列出了该管理器支持的功能,可以根据根据所列功能判断是否符合你的需求。
1.添加和移除并中断
2.自定义完成事件
3.延迟时间或帧数
4.指定执行次数
5.循环执行
6.是否受TimeScale影响

源码

代码中使用的MonoMgr是我实现的公共组件,方便外部代码调用MonoBehaviour,这部分可以根据自己的实际需求调整。其余部分开箱即用。
代码中有注释,没有太复杂的功能,就不过多解释了。

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

public class TimerMgr : Singleton<TimerMgr>
{
    public delegate void CompleteEvent();
    class TimerData
    {
        public int id;
        public CompleteEvent onCompleted; //完成回调事件
        public float time;   // 所需时间或帧数
        public float targetTime;   // 目标时间(如果是帧数则无效)
        public bool isIgnoreTimeScale;  // 是否忽略时间速率
        public bool isLoop;     //是否重复
        public int executeCount;   //循环次数
        public bool isSecond;   //是否以秒为单位 否则为帧数
        public Coroutine coroutine; //标记协程
    }

    int timerId = 0;
    Dictionary<int, TimerData> timerDict = new Dictionary<int, TimerData>();
    List<int> tempRemoveTimer = new List<int>();

    public TimerMgr()
    {
        //绑定Update
        MonoMgr.Instance.AddUpdateListener(UpdateTime);
    }

    void UpdateTime()
    {
        for(int i = timerDict.Count - 1; i >= 0 ; i--)
        {
            TimerData timeData = timerDict.ElementAt(i).Value;
            if (!timeData.isSecond)
            {
                continue;
            }

            float nowTime = TimeNow(timeData.isIgnoreTimeScale);
            if (nowTime >= timeData.targetTime)
            {
                timeData.onCompleted?.Invoke();
                timeData.executeCount -= 1;
                if (timeData.isLoop)
                {
                    timeData.targetTime = nowTime + timeData.time;
                }
                else
                {
                    if(timeData.executeCount <= 0)
                    {
                        tempRemoveTimer.Add(timeData.id);
                    }
                    else
                    {
                        timeData.targetTime = nowTime + timeData.time;
                    }
                }
            }
        }
        for(int i = 0; i < tempRemoveTimer.Count; i++)
        {
            RemoveTimer(tempRemoveTimer[i]);
        }
        tempRemoveTimer.Clear();
    }

    // 获取当前时间
    float TimeNow(bool isIgnoreTimeScale)
    {
        return isIgnoreTimeScale ? Time.realtimeSinceStartup : Time.time;
    }

    /// <summary>
    /// 创建一个新的定时器(支持循环)
    /// </summary>
    /// <param name="time">延迟时间(秒)</param>
    /// <param name="onCompleted">结束回调</param>
    /// <param name="isLoop">是否循环,false则只执行一次</param>
    /// <param name="isSecond">秒/帧数</param>
    /// <param name="isIgnoreTimeScale">是否受TimeScale影响</param>
    /// <returns></returns>
    public int CreateNewTimer(float time, CompleteEvent onCompleted, bool isLoop = false, bool isSecond = true,bool isIgnoreTimeScale = false)
    {
        timerId += 1;
        timerDict.Add(timerId, new TimerData()
        {
            id = timerId,
            onCompleted = onCompleted,
            time = time,
            targetTime = time + TimeNow(isIgnoreTimeScale),
            isIgnoreTimeScale = isIgnoreTimeScale,
            isLoop = isLoop,
            executeCount = 1,
            isSecond = isSecond
        });

        // 如果不是以秒为单位,则执行延迟帧数
        if (!isSecond)
        {
            timerDict[timerId].coroutine = MonoMgr.Instance.StartCoroutine(DelayedExecution(timerDict[timerId]));
        }
        return timerId;
    }

    /// <summary>
    /// 创建一个新的定时器(支持执行次数)
    /// </summary>
    /// <param name="time">延迟时间(秒)</param>
    /// <param name="onCompleted">结束回调</param>
    /// <param name="count">执行次数</param>
    /// <param name="isSecond">秒/帧数</param>
    /// <param name="isIgnoreTimeScale">是否受TimeScale影响</param>
    /// <returns></returns>
    public int CreateNewCountTimer(float time, CompleteEvent onCompleted, int count, bool isSecond = true, bool isIgnoreTimeScale = false)
    {
        timerId += 1;
        timerDict.Add(timerId, new TimerData()
        {
            id = timerId,
            onCompleted = onCompleted,
            time = time,
            targetTime = time + TimeNow(isIgnoreTimeScale),
            isIgnoreTimeScale = isIgnoreTimeScale,
            isLoop = false,
            executeCount = count,
            isSecond = isSecond
        });

        // 如果不是以秒为单位,则执行延迟帧数
        if (!isSecond)
        {
            timerDict[timerId].coroutine = MonoMgr.Instance.StartCoroutine(DelayedExecution(timerDict[timerId]));
        }
        return timerId;
    }

    /// <summary>
    /// 移除指定定时器
    /// </summary>
    public void RemoveTimer(int id)
    {
        if (timerDict.ContainsKey(id))
        {
            TimerData data = timerDict[id];
            if (!data.isSecond)
            {
                MonoMgr.Instance.StopCoroutine(data.coroutine);
            }
            data = null;
            timerDict.Remove(id);
        }
    }

    /// <summary>
    /// 清除所有定时器
    /// </summary>
    public void RemoveAllTimer()
    {
        for (int i = timerDict.Count - 1; i >= 0; i--)
        {
            int id = timerDict.ElementAt(i).Key;
            RemoveTimer(id);
        }
    }

    IEnumerator DelayedExecution(TimerData data)
    {
        // 等待指定的帧数
        for (int i = 0; i < data.time; i++)
        {
            yield return null; // 等待下一帧
        }
        // 执行动作
        data.onCompleted?.Invoke();
        data.executeCount -= 1;
        if (data.isLoop)
        {
            // 防止完成事件中移除了定时器,不判断会导致依然执行协程
            if(data != null && timerDict.ContainsKey(data.id))
            {
                data.coroutine = MonoMgr.Instance.StartCoroutine(DelayedExecution(data));
            }
        }
        else
        {
            if(data.executeCount <= 0)
            {
                RemoveTimer(data.id);
            }
            else
            {
                if (data != null && timerDict.ContainsKey(data.id))
                {
                    data.coroutine = MonoMgr.Instance.StartCoroutine(DelayedExecution(data));
                }
            }
        }
    }
}
  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Unity 3D模型管理器是一种工具,它用于管理和组织Unity引擎中使用的3D模型资源。它可以帮助开发人员更高效地管理大量的模型资源,并提供一些方便的功能,以提高开发流程。 首先,Unity 3D模型管理器可以将模型资源组织成层次结构,使开发人员可以轻松地浏览和搜索所需的模型。通过对模型进行分类和标签,开发人员可以更好地组织和管理模型资源。 其次,模型管理器可以提供一些基本的编辑功能,如模型缩放、旋转和位置调整。这些功能使开发人员能够方便地对模型进行微调和调整,以适应游戏场景的要求。 此外,模型管理器还可以提供一些高级功能,如模型预览和导入/导出。通过模型预览功能,开发人员可以在编辑器中直接查看模型的外观和动画效果,从而更好地调整和优化模型。而导入/导出功能则使开发人员可以方便地将模型资源导入到Unity中,并且可以将其导出到其他格式,以便在其他引擎或软件中使用。 最后,Unity 3D模型管理器还可以与其他工具和插件集成,以进一步提高开发效率。例如,它可以与版本控制系统集成,以便多人协作开发时更好地管理模型资源的冲突和变更。 总而言之,Unity 3D模型管理器是一个重要的工具,它可以帮助开发人员有效地管理和组织3D模型资源,提高开发效率和优化游戏的质量。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我寄人间雪满头丶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值