CCoroutine.cs 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281
  1. using UnityEngine;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. /// <summary>
  5. /// 所有CCoroutine返回yield指令对象的基类
  6. /// </summary>
  7. public class CCoroutineYieldBase
  8. {
  9. }
  10. /// <summary>
  11. /// 排他性的yield,在这个yield到下个yield完成之前,不允许其他的协程执行
  12. /// </summary>
  13. public class CHoldForSecond : CCoroutineYieldBase
  14. {
  15. public float m_interval = -1;
  16. /// <summary>
  17. /// 间隔时间
  18. /// </summary>
  19. /// <param name="timeoutTime">间隔时间,yield return之后至少要过这么久才又会调用过来,单位秒,在这段时间内主线程sleep等待</param>
  20. public CHoldForSecond(float interval = 0f)
  21. {
  22. m_interval = interval;
  23. }
  24. }
  25. /// <summary>
  26. /// 排他性的yield,在这个yield到下个yield完成之前,不允许其他的协程执行
  27. /// </summary>
  28. public class CWaitForSecond : CCoroutineYieldBase
  29. {
  30. public float m_interval = -1;
  31. /// <summary>
  32. /// 间隔时间
  33. /// </summary>
  34. /// <param name="timeoutTime">间隔时间,yield return之后至少要过这么久才又会调用过来,单位秒,在这段时间内主线程继续开始循环</param>
  35. public CWaitForSecond(float interval = -1)
  36. {
  37. m_interval = interval;
  38. }
  39. }
  40. /// <summary>
  41. /// 排他性的yield,在这个yield到下个yield完成之前,不允许其他的协程执行
  42. /// </summary>
  43. public class CWaitForNextFrame : CCoroutineYieldBase
  44. {
  45. }
  46. /// <summary>
  47. /// 之所以CCorourtineManager还需要用这个Monobehaviour去调用,就是由于如果CCorourtineManager直接是Monobehaviour,会自带
  48. /// StartCoroutine方法,而那个是我们的类不希望开发人员去调用的
  49. /// </summary>
  50. public class ____CCorourtineManagerMonobehaviour : SingletonMono<____CCorourtineManagerMonobehaviour>
  51. {
  52. public CCoroutineManager s_smartCoroutine = null;
  53. void Update()
  54. {
  55. if (null != s_smartCoroutine)
  56. {
  57. s_smartCoroutine.Update();
  58. }
  59. }
  60. }
  61. /// <summary>
  62. /// 代表一个协程任务
  63. /// </summary>
  64. public class CCoroutine
  65. {
  66. public IEnumerator iter = null;
  67. public CCoroutine(IEnumerator it)
  68. {
  69. iter = it;
  70. }
  71. public void Stop()
  72. {
  73. iter = null;
  74. }
  75. }
  76. /// <summary>
  77. /// 智能协程,能够很好利用每一帧的时间来做事,又尽量不卡渲染,用于平滑Loading时候的动画
  78. /// </summary>
  79. public class CCoroutineManager : Singleton<CCoroutineManager>
  80. {
  81. private System.DateTime m_lastFrameTime;
  82. private System.DateTime m_waitTillTime;
  83. private long m_lastTimeUpdateBeginTime = 0;
  84. private LinkedList<CCoroutine> m_execlusiveCoroutineList = new LinkedList<CCoroutine>();
  85. private int m_frameRate = 0;
  86. private double m_deltaMillSecondsPerFrame = 0;
  87. int sleepTime = 0;
  88. int WaitTime = 0;
  89. public override void Init()
  90. {
  91. ____CCorourtineManagerMonobehaviour.Instance.s_smartCoroutine = this;
  92. m_lastFrameTime = System.DateTime.Now;
  93. m_waitTillTime = System.DateTime.Now;
  94. m_frameRate = 30;
  95. m_deltaMillSecondsPerFrame = standardDeltaTime * 1;
  96. }
  97. private double standardDeltaTime
  98. {
  99. get
  100. {
  101. return 1000f / 30f;
  102. }
  103. }
  104. public void Update()
  105. {
  106. //WaitFormSeconds的时间还没到
  107. if (System.DateTime.Now <= m_waitTillTime)
  108. {
  109. return;
  110. }
  111. //ReEvaluateTimeCost();
  112. m_lastFrameTime = System.DateTime.Now;
  113. while ((System.DateTime.Now - m_lastFrameTime).TotalMilliseconds < m_deltaMillSecondsPerFrame
  114. && m_execlusiveCoroutineList.Count > 0)
  115. {
  116. LinkedListNode<CCoroutine> node = m_execlusiveCoroutineList.Last;
  117. var coroutine = node.Value.iter;
  118. if (!coroutine.MoveNext())
  119. {
  120. //协程已经执行完
  121. m_execlusiveCoroutineList.Remove(node);
  122. continue;
  123. }
  124. object handle = coroutine.Current;
  125. if (handle == null)
  126. {
  127. //协程已经执行完
  128. m_execlusiveCoroutineList.Remove(node);
  129. continue;
  130. }
  131. if (handle is CCoroutine)
  132. {
  133. continue;
  134. }
  135. if (handle is CHoldForSecond)
  136. {
  137. ProcessHoldForSeconds(handle as CHoldForSecond);
  138. }
  139. else if (handle is CWaitForSecond)
  140. {
  141. ProcessWaitForSeconds(handle as CWaitForSecond);
  142. break;
  143. }
  144. else if (handle is CWaitForNextFrame)
  145. {
  146. break;
  147. }
  148. else
  149. {
  150. DebugHelper.LogError("CCoroutine不支持" + handle.GetType() + "类型的yield return指令,请明确您需要做什么");
  151. }
  152. }
  153. m_lastFrameTime = System.DateTime.Now;
  154. }
  155. /// <summary>
  156. /// 重新评估m_deltaTimePerFrame是否合理,是否把帧之间的时间利用得当
  157. /// </summary>
  158. private System.DateTime m_lastEvaluateTime = System.DateTime.Now;
  159. private bool m_evaluateStart = false;
  160. private void ReEvaluateTimeCost()
  161. {
  162. if (m_evaluateStart == false)
  163. {
  164. m_lastEvaluateTime = System.DateTime.Now;
  165. m_evaluateStart = true;
  166. return;
  167. }
  168. System.DateTime evaluateTime = System.DateTime.Now;
  169. double diff = (evaluateTime - m_lastEvaluateTime).TotalMilliseconds;
  170. m_lastEvaluateTime = evaluateTime;
  171. if (diff > standardDeltaTime)
  172. {
  173. m_deltaMillSecondsPerFrame = System.Math.Max(standardDeltaTime * 0.3f, m_deltaMillSecondsPerFrame - (diff - standardDeltaTime));
  174. }
  175. else if (m_deltaMillSecondsPerFrame < standardDeltaTime * 0.75f)
  176. {
  177. m_deltaMillSecondsPerFrame += 1; //如果用于loading的时间太短,就尝试开始增加
  178. }
  179. }
  180. private void ProcessHoldForSeconds(CHoldForSecond handle)
  181. {
  182. if (handle.m_interval > 0)
  183. {
  184. sleepTime += (int)(handle.m_interval * 1000);
  185. System.Threading.Thread.Sleep((int)(handle.m_interval * 1000f));
  186. }
  187. }
  188. private void ProcessWaitForSeconds(CWaitForSecond handle)
  189. {
  190. if (handle.m_interval > 0)
  191. {
  192. WaitTime += (int)(handle.m_interval * 1000);
  193. m_waitTillTime = System.DateTime.Now.AddSeconds(handle.m_interval);
  194. }
  195. }
  196. /// <summary>
  197. /// 开始协程
  198. /// </summary>
  199. /// <param name="coroutine"></param>
  200. public CCoroutine StartCoroutine(IEnumerator coroutine)
  201. {
  202. CCoroutine cor = new CCoroutine(coroutine);
  203. m_execlusiveCoroutineList.AddLast(cor);
  204. return cor;
  205. }
  206. /// <summary>
  207. /// 停止一个协程
  208. /// </summary>
  209. /// <param name="c"></param>
  210. public void StopCoroutine(CCoroutine c, bool stopChild = true)
  211. {
  212. if (c != null)
  213. {
  214. c.Stop();
  215. bool foundChild = false;
  216. var iter = m_execlusiveCoroutineList.GetEnumerator();
  217. while (iter.MoveNext())
  218. {
  219. if (iter.Current == c)
  220. {
  221. foundChild = true;
  222. break;
  223. }
  224. }
  225. if (!stopChild)
  226. {
  227. if (foundChild)
  228. {
  229. m_execlusiveCoroutineList.Remove(iter.Current);
  230. }
  231. return;
  232. }
  233. else
  234. {
  235. if (foundChild)
  236. {
  237. CCoroutine last = m_execlusiveCoroutineList.Last.Value;
  238. while (last != c)
  239. {
  240. m_execlusiveCoroutineList.RemoveLast();
  241. last = m_execlusiveCoroutineList.Last.Value;
  242. }
  243. m_execlusiveCoroutineList.RemoveLast();
  244. }
  245. }
  246. }
  247. }
  248. }