Unity3D 任务系统设计

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

原文地址:https://www.cnblogs.com/binpan/p/4290515.html