參考 : “海游移動” 博客 http://jxwgame.blog.51cto.com/943299/1602630
先考慮需求
在任何時候,我需要能夠通過new創建一個任務(完成事件,獲得獎勵),任務自動開始運行 ,並且自動判斷運行狀態,是否完成等。
我們要做的,只是創建這個任務,並賦一些完成條件。
所以任務類(Class MyTask) 必須是脫離於Mono的獨立類。並且有一些對任務的控制(開始,暫停,完成)。
大致如下
1 public class MyTask 2 { 3 public MyTask() 4 { 5 //構造一個任務並且自動開始 6 //createTask 7 } 8 }
任務建立后,需要不停地監測任務的狀態,是個循環,在u3d中只能通過協程,而這個類不繼承mono是沒有協程的
所以建立一個TaskManager類,繼承自mono。用來創建並且監測。
1 public class MyTaskManager:MonoBehavior 2 { 3 static MyTaskManager singleton; 4 5 public static TaskState CreateTask() 6 { 7 //專門用來startCorutine 8 if(singleton == null) 9 { 10 GameObject go = new GameObject("MyTaskManager"); 11 singleton = go.AddComponent<MyTaskManager>(); 12 } 13 14 //既然要創建對象,那么創建完成之后就必須返回給Task類。所以還要建立一個TaskState類用來返回 15 return new TaskState(); 16 } 17 18 //不繼承mono 19 public class TaskState 20 { 21 22 23 } 24 }
完整的3部分代碼:
1 using UnityEngine; 2 using System.Collections; 3 4 /// <summary> 5 /// 任務類,用來被調用 6 /// </summary> 7 public class MyTask 8 { 9 //string TaskName; 10 11 MyTaskManager.TaskState task; 12 13 public delegate void FinishedHander(bool isFinished); 14 public event FinishedHander Finished; 15 16 public MyTask(IEnumerator c,bool autoStart = true) 17 { 18 //構造一個任務並且自動開始 19 //由於需要協程(檢測運行狀態),所以只能再寫一個類來提供 20 task = MyTaskManager.CreateTask(c); 21 22 //將本類中的TaskFinished 加入到 MyTaskManager中的TaskFinished。 所以 在myTaskManager中調用的時候, 23 //會先調用myTaskmanager的taskState中的,然后再調用本類中的 24 task.Finished += TaskFinished; 25 26 if(autoStart) 27 { 28 //創建完之后運行 29 task.Start(); 30 } 31 32 } 33 34 35 void TaskFinished(bool isFinished) 36 { 37 FinishedHander handler = Finished; 38 if(handler!=null) 39 { 40 handler(isFinished); 41 } 42 } 43 44 45 //任務有 停止,繼續,終結等處理方式 46 public void Pause() 47 { 48 task.Pause(); 49 } 50 51 public void Resume() 52 { 53 task.Resume(); 54 } 55 56 public void Finish() 57 { 58 task.Finish(); 59 } 60 61 }
1 using UnityEngine; 2 using System.Collections; 3 4 /// <summary> 5 /// 提供給MyTask類輔助 6 /// </summary> 7 public class MyTaskManager : MonoBehaviour 8 { 9 10 //單例 11 static MyTaskManager singleton; 12 public static TaskState CreateTask(IEnumerator c) 13 { 14 //既然要創建對象,那么創建完后就要返回,所以必須有個返回的類 15 if(singleton == null) 16 { 17 GameObject go = new GameObject("MyTaskManager"); 18 singleton = go.AddComponent<MyTaskManager>(); 19 } 20 return new TaskState(c); 21 } 22 23 24 25 26 //類 類 27 public class TaskState 28 { 29 IEnumerator coroutine; //用來保存傳遞過來的函數。 30 public enum State 31 { 32 Running,//正在運行 33 Paused, //暫停 34 Stopped,//停止/放棄 35 Finished,//完成 36 } 37 38 public State state; 39 40 public delegate void FinishedHander(bool isFinished); 41 public event FinishedHander Finished; 42 43 public TaskState(IEnumerator c) 44 { 45 coroutine = c; 46 state = State.Running; 47 } 48 49 50 public void Start() 51 { 52 //改變任務的狀態,並且開啟一個監測協程 53 state = State.Running; 54 singleton.StartCoroutine(TaskStateMonitor()); 55 } 56 57 //與task中的操作相對應 58 public void Pause() 59 { 60 state = State.Paused; 61 } 62 public void Resume() 63 { 64 if (state == State.Paused) 65 { 66 state = State.Running; 67 } 68 } 69 public void Finish() 70 { 71 state = State.Finished; 72 } 73 74 //主要是用來判斷是否完成任務 75 IEnumerator TaskStateMonitor() 76 { 77 yield return null; 78 IEnumerator e = coroutine; 79 while(state == State.Running) 80 { 81 if (state == State.Paused) 82 yield return null; 83 else 84 { 85 //IEnumerator 有current ,movenext,reset 86 //就是說不停地執行 new出來的任務,因為new出來的任務是Enumrator,直到不能movenext了 87 if(e !=null && e.MoveNext()) 88 { 89 yield return e.Current; 90 } 91 else 92 { 93 state = State.Finished; 94 } 95 } 96 } 97 FinishedHander handler = Finished; 98 if (handler != null) 99 handler(true); //true 100 101 } 102 103 } 104 }
1 using UnityEngine; 2 using System.Collections; 3 4 /// <summary> 5 /// 使用示例 6 /// </summary> 7 public class UseTask : MonoBehaviour 8 { 9 10 IEnumerator TaskOne() 11 { 12 while(true) 13 { 14 Debug.Log("TaskOne running"); 15 if(CheckTaskOneFinished()) 16 { 17 Debug.Log("TaskOne Finished"); 18 DealWithTaskOneFinished(); 19 break; //跳出后 執行e.moveNext()就沒有了,狀態就finished 20 } 21 yield return null; 22 } 23 } 24 25 /// <summary> 26 /// 用來檢測任務是否完成,里面放條件 27 /// </summary> 28 /// <returns></returns> 29 bool CheckTaskOneFinished() 30 { 31 if(Time.time >3) 32 { 33 return true; 34 } 35 else 36 { 37 return false; 38 } 39 } 40 41 void DealWithTaskOneFinished() 42 { 43 /// 44 } 45 46 47 void Start() 48 { 49 MyTask task = new MyTask(TaskOne()); 50 51 //匿名添加finished后的操作。 52 task.Finished += delegate(bool value) 53 { 54 if(value) 55 { 56 Debug.Log("after 匿名 finished"); 57 } 58 }; 59 60 } 61 62 }
執行結果:

可以自行加一些任務的處理。完善整個系統。
重要幾點:
1: IEnumerator : 我的理解是一個類似Interator的接口,它有三個方法。current,movenext,reset 。
每次就movenext去執行,執行到yield 位置。
2: yiled return: 每次調用到yield 的時候,就返回,下次在yiled之后的地方繼續執行。
3: event 調用順序 。 TaskState -> myTask 。所有的finished事件都是注冊到TaskState中的。
所以當上述的任務正在執行的時候,會一直在while循環中,一直可以movenext,一旦完成條件達到,跳出循環。則movenext馬上為null,
改變state為Finished。通過事件層層調用注冊的函數去執行。
