参考 : “海游移动” 博客 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。通过事件层层调用注册的函数去执行。