• unity之 协程Coroutine VS 定时器


    unity协程Coroutine 大家并不陌生,在项目中也是经常使用。大量的使用协程,会影响性能,带来GC。

    如下图 延迟调用 所带来的的GC:

     

    因此 对于延迟调用 ,最好不要用 协程 Coroutine,最好自己用update 去实现。

    自己写定时器有哪些优点:

    1.减少GC

    2.可以自己写回调,开始执行,执行中,执行完毕回调。

    3.可以循环次数、暂定、停止、恢复、循环间隔时间、剩余循环次数。

    根据以上的需求,该如何设计出一个优雅且好用的定时器呢?

     

     

     

    定时器:

      1 using System;
      2 
      3 /// <summary>
      4 /// 定时器
      5 /// </summary>
      6 public class TestTimeAction
      7 {
      8     /// <summary>
      9     /// 定时器名字
     10     /// </summary>
     11     private string m_Name;
     12 
     13     /// <summary>
     14     /// 定时器名字
     15     /// </summary>
     16     internal string Name
     17     {
     18         get { return m_Name; }
     19     }
     20 
     21     /// <summary>
     22     /// 延迟时间
     23     /// </summary>
     24     private float m_DelayTime;
     25 
     26     /// <summary>
     27     /// 循环次数 -1:无线循环  0:循环一次  >0:循环次数
     28     /// </summary>
     29     private int m_LoopTimes;
     30 
     31     /// <summary>
     32     /// 已循环次数
     33     /// </summary>
     34     private int m_AlreadyTimes;
     35 
     36     /// <summary>
     37     /// 间隔
     38     /// </summary>
     39     private float m_Interval;
     40 
     41     /// <summary>
     42     /// 是否正在运行
     43     /// </summary>
     44     public bool IsRuning
     45     {
     46         get;
     47         private set;
     48     }
     49 
     50     /// <summary>
     51     /// 是否暂定中
     52     /// </summary>
     53     private bool m_IsPause = false;
     54 
     55     /// <summary>
     56     /// 最后暂停时间
     57     /// </summary>
     58     private float m_LastPauseTime;
     59 
     60     /// <summary>
     61     /// 暂停了多久
     62     /// </summary>
     63     private float m_PauseTime;
     64 
     65     /// <summary>
     66     /// 当前时间
     67     /// </summary>
     68     private float m_CurrTime;
     69 
     70     //开始、运行中、完成回调
     71     public Action OnStartFun { get; private set; }
     72     public Action<int> OnDoingFun { get; private set; }//剩余次数
     73     public Action OnCompleteFun { get; private set; }
     74 
     75     /// <summary>
     76     /// 初始化
     77     /// </summary>
     78     internal TestTimeAction Init(string name, float delayTime, int loopTimes, float interval, Action startFun, Action<int> doingFun, Action completeFun)
     79     {
     80         m_Name = name;
     81         m_DelayTime = delayTime;
     82         m_LoopTimes = loopTimes;
     83         m_Interval = interval;
     84         OnStartFun = startFun;
     85         OnDoingFun = doingFun;
     86         OnCompleteFun = completeFun;
     87         return this;
     88     }
     89 
     90     /// <summary>
     91     /// 运行
     92     /// </summary>
     93     public void Run()
     94     {
     95         TestGameEntry.TimeMgr.RegisterTimeAction(this);
     96         m_CurrTime = UnityEngine.Time.time;
     97         m_IsPause = false;
     98     }
     99 
    100     /// <summary>
    101     /// 暂停
    102     /// </summary>
    103     public void Pause()
    104     {
    105         if (m_IsPause) return;
    106         m_LastPauseTime = UnityEngine.Time.time;
    107         m_IsPause = true;
    108     }
    109 
    110     /// <summary>
    111     /// 恢复
    112     /// </summary>
    113     public void Resume()
    114     {
    115         m_IsPause = false;
    116         //计算暂停多久
    117         m_PauseTime = UnityEngine.Time.time - m_LastPauseTime;
    118     }
    119 
    120     /// <summary>
    121     /// 停止
    122     /// </summary>
    123     private void Stop()
    124     {
    125         IsRuning = false;
    126         OnCompleteFun?.Invoke();
    127         TestGameEntry.TimeMgr.RemoveTimeAction(this);
    128     }
    129 
    130     internal void OnUpdate()
    131     {
    132         if (m_IsPause) return;
    133         //开始运行
    134         if (UnityEngine.Time.time > m_CurrTime + m_DelayTime + m_PauseTime)
    135         {
    136             if (!IsRuning)
    137             {
    138                 IsRuning = true;
    139                 m_CurrTime = UnityEngine.Time.time;
    140                 m_PauseTime = 0;
    141                 OnStartFun?.Invoke();
    142             }
    143         }
    144         if (!IsRuning) return;
    145         //运行中
    146         if (UnityEngine.Time.time > m_CurrTime + m_PauseTime)
    147         {
    148             m_CurrTime = UnityEngine.Time.time + m_Interval;
    149             m_PauseTime = 0;
    150             OnDoingFun?.Invoke(m_LoopTimes - m_AlreadyTimes);
    151             if (m_LoopTimes > -1)
    152             {
    153                 m_AlreadyTimes++;
    154                 if (m_AlreadyTimes >= m_LoopTimes)
    155                 {
    156                     Stop();
    157                 }
    158             }
    159         }
    160     }
    161 }
    View Code

     

    时间管理器:

     1 using System.Collections.Generic;
     2 
     3 public class TestTimeManager : System.IDisposable
     4 {
     5     private LinkedList<TestTimeAction> testTimeActions;
     6 
     7     internal void Init()
     8     {
     9         testTimeActions = new LinkedList<TestTimeAction>();
    10     }
    11 
    12     public TestTimeAction CreateTimeAction()
    13     {
    14         TestTimeAction timeAction = new TestTimeAction();
    15         return timeAction;
    16     }
    17 
    18 
    19     public void RegisterTimeAction(TestTimeAction timeAction)
    20     {
    21         testTimeActions.AddLast(timeAction);
    22     }
    23 
    24     public void RemoveTimeAction(TestTimeAction timeAction)
    25     {
    26         if (testTimeActions.Contains(timeAction))
    27         {
    28             testTimeActions.Remove(timeAction);
    29         }
    30     }
    31     public void RemoveTimeActionByName(string name)
    32     {
    33         for (var v = testTimeActions.First; v.Next != null; v = v.Next)
    34         {
    35             if (v.Value.Name.Equals(name, System.StringComparison.CurrentCultureIgnoreCase))
    36             {
    37                 testTimeActions.Remove(v.Value);
    38                 break;
    39             }
    40         }
    41     }
    42 
    43     public void OnUpdate()
    44     {
    45         for (var v = testTimeActions.First; v != null; v = v.Next)
    46         {
    47             if (v.Value.OnStartFun.Target == null || v.Value.OnStartFun.Target.ToString() == "null")
    48             {
    49                 testTimeActions.Remove(v);
    50                 continue;
    51             }
    52             if (v.Value.OnDoingFun.Target == null || v.Value.OnDoingFun.Target.ToString() == "null")
    53             {
    54                 testTimeActions.Remove(v);
    55                 continue;
    56             }
    57             if (v.Value.OnCompleteFun.Target == null || v.Value.OnCompleteFun.Target.ToString() == "null")
    58             {
    59                 testTimeActions.Remove(v);
    60                 continue;
    61             }
    62             v.Value.OnUpdate();
    63         }
    64     }
    65 
    66     public void Dispose()
    67     {
    68         testTimeActions.Clear();
    69     }
    70 }
    View Code

     

    测试入口

     1 using UnityEngine;
     2 
     3 public class TestGameEntry : MonoBehaviour
     4 {
     5     public static TestGameEntry Instance;
     6     public static TestTimeManager TimeMgr { get; private set; }
     7     private void Awake()
     8     {
     9         Instance = this;
    10     }
    11 
    12     void Start()
    13     {
    14         InitManagers();
    15         Init();
    16     }
    17 
    18     void InitManagers()
    19     {
    20         TimeMgr = new TestTimeManager();
    21     }
    22 
    23     void Init()
    24     {
    25         TimeMgr.Init();
    26     }
    27 
    28     void Update()
    29     {
    30         TimeMgr.OnUpdate();
    31     }
    32 
    33     private void OnDestroy()
    34     {
    35         TimeMgr.Dispose();
    36     }
    37 }
    View Code

     

    测试用例:

     1 if (Input.GetKeyUp(KeyCode.A))
     2         {
     3             timeAction = TestGameEntry.TimeMgr.CreateTimeAction();
     4             Debug.Log("创建了定时器time1");
     5             if (timeAction == null) return;
     6             timeAction.Init("time1", 10f, 100, 1f, () =>
     7              {
     8                  Debug.Log("time1 开始执行");
     9              }, (int times) =>
    10              {
    11                  Debug.Log(string.Format("time1 运行中,剩余{0}次", times));
    12              }, () =>
    13              {
    14                  Debug.Log("time1 完成");
    15              }).Run();
    16         }
    17 
    18         if (Input.GetKeyUp(KeyCode.P))
    19         {
    20             if (timeAction == null) return;
    21             timeAction.Pause();
    22             Debug.LogError("暂停");
    23         }
    24 
    25         if (Input.GetKeyUp(KeyCode.R))
    26         {
    27             if (timeAction == null) return;
    28             timeAction.Resume();
    29             Debug.LogError("恢复");
    30         }
    View Code

     

     

     欢迎大家提出批评建议和指教哈~

     

  • 相关阅读:
    高可用架构案例一
    小程序页面可以放置转发按钮,同时开放了微信运动步数背景音乐播放等更多基础能力
    [今日干货]微博如何才能快速增粉?
    [今日干货]短视频获得种子用户的途径
    【今日干货】分享个微信解绑手机号的方法
    群用户通过微信小程序可以更好地协作了
    微信小程序首支视频广告片发布
    微信公众号可快速创建“门店小程序” 不用开发
    公众号和小程序可以同名了 名称支持同主体复用
    公众号群发文章支持添加小程序
  • 原文地址:https://www.cnblogs.com/zhaolaosan/p/16183080.html
Copyright © 2020-2023  润新知