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

 

 

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

 

posted @ 2022-04-25 20:27  赵不灰  阅读(477)  评论(0编辑  收藏  举报