(Coroutine)管理類——TaskManager工具分享
By D.S.Qiu
尊重他人的勞動,支援原創,轉載請註明出處:http.dsqiu.iteye.com
在分享 vp_Timer 中提到,沒有繼承的MonoBehaviour,沒有Update,InVoke 和StartCoroutine的機制,vp_Timer就是提供了InVoke的機制,而且還可以統一管理。本篇D.S.Qiu要分享的TaskManager就是一個協程 管理類。 TaskManager —— Unity3D Managed Coroutines with Start, Stop, Resume ,看著就覺得很強大,當然是對於我這種對協程理解不深的來說。下面貼出 The Motivation of the author:
/// The motivation for this is twofold: /// /// 1. The existing coroutine API provides no means of stopping specific /// coroutines; StopCoroutine only takes a string argument, and it stops /// all coroutines started with that same string; there is no way to stop /// coroutines which were started directly from an enumerator. This is /// not robust enough and is also probably pretty inefficient. /// /// 2. StartCoroutine and friends are MonoBehaviour methods. This means /// that in order to start a coroutine, a user typically must have some /// component reference handy. There are legitimate cases where such a /// constraint is inconvenient. This implementation hides that /// constraint from the user. 程式碼很簡單,但卻很解渴,Unity官方只聽過了StopCoroutine(string methodName)或StopAllCoroutine() 這兩個停止方法,從api就會覺得Unity的整體方法論還不完善,所以才會覺得TaskManager的難能可貴。由於原始碼簡單,就不做解釋了,See source for document : C#程式碼 收藏程式碼 /// Simple, really. There is no need to initialize or even refer to TaskManager. /// When the first Task is created in an application, a "TaskManager" GameObject /// will automatically be added to the scene root with the TaskManager component /// attached. This component will be responsible for dispatching all coroutines /// behind the scenes. /// /// Task also provides an event that is triggered when the coroutine exits. using UnityEngine; using System.Collections; /// A Task object represents a coroutine. Tasks can be started, paused, and stopped. /// It is an error to attempt to start a task that has been stopped or which has /// naturally terminated. public class Task { /// Returns true if and only if the coroutine is running. Paused tasks /// are considered to be running. public bool Running { get { return task.Running; } } /// Returns true if and only if the coroutine is currently paused. public bool Paused { get { return task.Paused; } } /// Delegate for termination subscribers. manual is true if and only if /// the coroutine was stopped with an explicit call to Stop(). public delegate void FinishedHandler(bool manual); /// Termination event. Triggered when the coroutine completes execution. public event FinishedHandler Finished; /// Creates a new Task object for the given coroutine. /// /// If autoStart is true (default) the task is automatically started /// upon construction. public Task(IEnumerator c, bool autoStart = true) { task = TaskManager.CreateTask(c); task.Finished += TaskFinished; if(autoStart) Start(); } /// Begins execution of the coroutine public void Start() { task.Start(); } /// Discontinues execution of the coroutine at its next yield. public void Stop() { task.Stop(); } public void Pause() { task.Pause(); } public void Unpause() { task.Unpause(); } void TaskFinished(bool manual) { FinishedHandler handler = Finished; if(handler != null) handler(manual); } TaskManager.TaskState task; } class TaskManager : MonoBehaviour { public class TaskState { public bool Running { get { return running; } } public bool Paused { get { return paused; } } public delegate void FinishedHandler(bool manual); public event FinishedHandler Finished; IEnumerator coroutine; bool running; bool paused; bool stopped; public TaskState(IEnumerator c) { coroutine = c; } public void Pause() { paused = true; } public void Unpause() { paused = false; } public void Start() { running = true; singleton.StartCoroutine(CallWrapper()); } public void Stop() { stopped = true; running = false; } IEnumerator CallWrapper() { yield return null; IEnumerator e = coroutine; while(running) { if(paused) yield return null; else { if(e != null && e.MoveNext()) { yield return e.Current; } else { running = false; } } } FinishedHandler handler = Finished; if(handler != null) handler(stopped); } } static TaskManager singleton; public static TaskState CreateTask(IEnumerator coroutine) { if(singleton == null) { GameObject go = new GameObject("TaskManager"); singleton = go.AddComponent<TaskManager>(); } return new TaskState(coroutine); } }
Usage Example: C#程式碼 收藏程式碼 /// Example usage: /// /// ---------------------------------------------------------------------------- /// IEnumerator MyAwesomeTask() /// { /// while(true) { /// Debug.Log("Logcat iz in ur consolez, spammin u wif messagez."); /// yield return null; //// } /// } /// /// IEnumerator TaskKiller(float delay, Task t) /// { /// yield return new WaitForSeconds(delay); /// t.Stop(); /// } /// /// void SomeCodeThatCouldBeAnywhereInTheUniverse() /// { /// Task spam = new Task(MyAwesomeTask()); /// new Task(TaskKiller(5, spam)); /// } /// ----------------------------------------------------------------------------
小結:
本文主要是分享我的收藏的一些“乾貨”,TaskManager 和 vp_Timer 在專案中發揮了很大的作用,D.S.Qiu 一再覺得強大的東西不都是複雜的,能夠使用最簡單的本質方法解決問題才是程式碼設計的追求。 文末附上了相關的連結以及TaskManager的程式碼。
如果您對D.S.Qiu有任何建議或意見可以在文章後面評論,或者發郵件(gd.s.qiu@gmail.com)交流,您的鼓勵和支援是我前進的動力,希望能有更多更好的分享。
轉載請在文首註明出處:http://dsqiu.iteye.com/blog/2022992
更多精彩請關注D.S.Qiu的部落格和微博(ID:靜水逐風)
參考:
①Unity-TaskManager:https://github.com/krockot/Unity-TaskManager
②Programmer Instincts:http://programmerinstincts.com/214/