zoukankan      html  css  js  c++  java
  • Unity3D延迟回调的封装

      最近,整理项目框架逻辑时,无意中翻到n年前封装的延迟回调管理器,就拎出来说道说道:

      先说一下系统提供的几种常用的延迟回调方式:

    1)Invoke(Invoke、CancelInvoke):首先需要继承自MonoBehaviour,其次使用的是函数名作为参数调用,比较麻烦,容易出错(运行时才会审查,编译检查不到);
    2)Coroutine(StartCoroutine、StopCoroutine):仍然继承自MonoBehaviour,调用时可以使用函数名,也可以直接传入委托,效率上不高,每次调用都会牵扯到额外的堆内存分配,并且所挂载的游戏对象状态不能被打断,否则执行也会被打断;
    3、Update:依赖MonoBehaviour,每次调用需要单独申请变量,重写逻辑,也会因状态打断而停止执行;
    在不使用插件的情况下,索性进行一些封装,综合各自的优点,去其糟粕:

    public class InvokeManager
    {
        private InvokeManager()    //泛型单件
        {
            timeDelayLst = new List<float>();
            timeStateLst = new List<bool>();
            callbackDelayLst = new List<System.Action>();
        }
    
        private IList<float> timeDelayLst;
        private IList<bool> timeStateLst;
        private IList<System.Action> callbackDelayLst;
    
        public void Invoke(float _timeDelay, System.Action _callback)
        {
            timeDelayLst.Add(_timeDelay);
            timeStateLst.Add(false);
            callbackDelayLst.Add(_callback);
        }
        public int CancelInvoke(System.Action _callback, bool _cancelAll = false)    //false:仅取消最后注册的(和延迟时间无关);返回int型,可以根据剩余的次数立即执行未执行的回调函数
        {
            int tCount = 0;
            for(int i = callbackDelayLst.Count - 1; i >= 0; i--)
            {
                if(callbackDelayLst[i].Equals(_callback))
                {
                    tCount++;
                    timeDelayLst.RemoveAt(i);
                    timeStateLst.RemoveAt(i);
                    callbackDelayLst.RemoveAt(i);
                    if(!_cancelAll)
                    {
                        return tCount;
                    }
                }
            }
            return tCount;
        }
        public void ClearInvoke()
        {
            timeDelayLst.Clear();
            timeStateLst.Clear();
            callbackDelayLst.Clear();
        }
        public void TickUpdate(float _deltaTime)
        {
            filtTick(_deltaTime);
            for(int i = timeStateLst.Count - 1; i >= 0; i--)
            {
                timeStateLst[i] = false;
            }
        }
      private void filtTick(float _deltaTime)
      {
        for(int i = timeDelayLst.Count - 1; i >= 0; i--)
        {
          if(timeStateLst.Count > i && !timeStateLst[i])
          {
            timeDelayLst[i] -= _deltaTime;
            timeStateLst[i] = true;
            if(timeDelayLst[i] <= 0)
            {
              var tCallback = callbackDelayLst[i];//从后向前遍历:删除最后注册(和延迟时间无关)的事件回调(可以自行扩展根据延迟时间进行删除)    
              timeDelayLst.RemoveAt(i);
              timeStateLst.RemoveAt(i);
              callbackDelayLst.RemoveAt(i);
    
              tCallback();
              filtTick(_deltaTime);
            }
          }
        }
      }
    }        

    封装之后仅需要在主函数逻辑中进行驱动计时,之后就可以根据需要方便的延迟及取消延迟了。(PS:因为只是简单的封装,因此还有以下缺点:1)递归回调的问题;2)无法取消匿名的回调函数。)
    当然,也有一些比较方便使用的插件,这个可以根据需要自行研究了,eg:Vision Timer等,DoTween等也有提供接口功能。

  • 相关阅读:
    用于json的 .ashx 小细节
    (转)写让别人能读懂的代码
    Mvc 中ViewBag Model 查找不到解决
    Windows 2008 R2 配置 DNS 实现二级域名
    Windows Server 2008 DNS服务器安装与配置
    【iOS】swift init构造器
    【iOS】OC-UTC日期字符串格式化
    android使用sharesdk的小感
    【iOS】Swift GCD-下
    【iOS】Swift GCD-上
  • 原文地址:https://www.cnblogs.com/wayland/p/6229233.html
Copyright © 2011-2022 走看看