`

Unity协程(Coroutine)管理类——TaskManager工具分享

阅读更多

Unity协程(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 :

/// 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:

/// 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:静水逐风)

 

 

 

 

 

 

参考:

krockot / Unity-TaskManagerhttps://github.com/krockot/Unity-TaskManager

②Programmer Instincts:http://programmerinstincts.com/214/

3
0
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics