Unity3D行为树插件Behave学习笔记
2015-12-25 13:13 阿诚de窝 阅读(3314) 评论(0) 编辑 收藏 举报Behave1.4行为树插件
下载地址:http://pan.baidu.com/s/1i4uuX0L
安装插件和使用
我们先来看看插件的安装和基本使用方法,新建一个Unity3D项目,这里我使用的是5.0以上的版本:
导入插件
第一步当然是导入下载好的插件包了,操作略过...
创建资源
首先我们创建一个名为BT的文件夹,点击Project面板的create来创建相应的资源:
我们会在Asset目录下生成一个NewBehaveLibrary0.asset的文件,我们重命名为MyBehaveLibrary后将其拖入新建的BT文件夹中即可。
编辑资源
我们选中创建的资源,在Inspector中可以看到如下的界面:
我们点击Edit library后会弹出两个窗口,需要注意的是有一个窗口被另一个完全覆盖了,拖拽一下就可以看到了。点击behave browse面板的create创建一个collection,再点击一次create创建一个tree我们就有了一个行为树了。
接下来我们选中新创建的NewTree1在behave editor面板就可以编辑这个行为树了。
我们将面板下方的Action拖拽到面板中并在Inspector修改该节点的名称为MyAction:
接下来我们在顶部中间的方块拉出一条线,连线到我们的MyAction顶上,这样就把这个节点添加到该行为树上了。
好了到目前为止,我们的编辑就算是完成了。
编译资源
到目前为止,我们的资源还不能在项目中直接使用,我们需要先对其进行编译,选中我们的library,在Inspector中会出现选项:
我们点击一下Build library debug就可以编译出在项目中可以使用的资源了,如下:
编辑代码
编辑完成后,接下来我们该怎么使用行为树呢?看官们请接着看。
首先我们创建一个类Demo1Agent:
1 using Behave.Runtime; 2 using UnityEngine; 3 using System.Collections; 4 using Tree = Behave.Runtime.Tree; 5 6 public class Demo1Agent : IAgent { 7 8 public void Reset (Tree sender) { 9 10 } 11 12 public int SelectTopPriority (Tree sender, params int[] IDs) { 13 return 0; 14 } 15 16 public BehaveResult Tick (Tree sender, bool init) { 17 Debug.Log("调用系统的Tick方法"); 18 return BehaveResult.Success; 19 } 20 21 public BehaveResult TickMyActionAction(Tree sender) { 22 Debug.Log("我的action"); 23 return BehaveResult.Success; 24 } 25 }
我们创建了一个实现了IAgent的类,这个类会和一个行为树进行绑定,这里需要注意的是Tick和TickMyActionAction方法,在一个行为树中,同一时刻只有一个节点会执行,而我们的“MyAction”执行时,会寻找TickMyActionAction方法进行调用,这里的方法命名有一个规则:“Tick”+节点名称+“Action”,如果行为树找到了对应当前节点名称的方法就会进行调用,否则会调用Tick方法。
接下来我们创建一个类Demo1:
1 using UnityEngine; 2 using System.Collections; 3 using Behave.Runtime; 4 using Tree = Behave.Runtime.Tree; 5 6 public class Demo1 : MonoBehaviour { 7 8 Tree m_Tree; 9 Demo1Agent agent; 10 11 void Start () { 12 agent = new Demo1Agent (); 13 m_Tree = BLMyBehaveLibrary.InstantiateTree(BLMyBehaveLibrary.TreeType.NewCollection1_NewTree1, agent); 14 } 15 16 void Update () { 17 m_Tree.Tick(); 18 } 19 }
这个类就比较简单了,我们通过BLMyBehaveLibrary创建一个和Demo1Agent的实例绑定的行为树,其中BLMyBehaveLibrary和NewCollection1_NewTree1都是我们之前编辑好编译生成的行为树代码,每帧调用行为树的Tick方法即可。
调试行为树
我们在场景中添加一个GameObject并绑定Demo1即可,运行就可以看到“我的Action”的输出了。
节点详解
目前behave提供了下面6个节点,我们来具体的看看:
Action
动作节点,执行核心逻辑的节点,该节点我们之前已经使用过了,主要用来实现我们需要的逻辑功能。
这里主要说一下Tick方法的3个返回值:
1 namespace Behave.Runtime 2 { 3 public enum BehaveResult 4 { 5 Running, 6 Success, 7 Failure 8 } 9 }
- Running表示当前节点需要继续运行,下一次Tick时仍然会执行该节点。
- Success表示节点执行完毕,而且执行成功。
- Failure表示节点执行完毕,而且执行失败。
Decorator
装饰节点只会有一个子节点,作用为通过判断来控制是否执行其子节点,我们来看看装饰节点的使用方法:
首先我们创建一个新的行为树,并添加一个装饰节点和一个动作节点:
我们新建一个Demo2Agent:
1 using Behave.Runtime; 2 using UnityEngine; 3 using System.Collections; 4 using Tree = Behave.Runtime.Tree; 5 6 public class Demo2Agent : IAgent { 7 8 private bool _shoulDo; 9 10 public void Reset (Tree sender) { 11 12 } 13 14 public int SelectTopPriority (Tree sender, params int[] IDs) { 15 return 0; 16 } 17 18 public BehaveResult Tick (Tree sender, bool init) { 19 Debug.Log("调用系统的Tick方法"); 20 return BehaveResult.Success; 21 } 22 23 public BehaveResult TickMyDecoratorDecorator(Tree sender) { 24 _shoulDo = !_shoulDo; 25 if (_shoulDo) { 26 Debug.Log("执行子节点"); 27 return BehaveResult.Success; 28 } else { 29 Debug.Log("不执行子节点"); 30 return BehaveResult.Failure; 31 } 32 } 33 34 public BehaveResult TickMyActionAction(Tree sender) { 35 Debug.Log("我的action"); 36 return BehaveResult.Success; 37 } 38 }
这里要注意的是,装饰节点的命名为:“Tick”+节点名称+“Decorator”,不是Action了。
接下来编译我们的行为树,添加一个类Demo2:
1 using UnityEngine; 2 using System.Collections; 3 using Behave.Runtime; 4 using Tree = Behave.Runtime.Tree; 5 6 public class Demo2 : MonoBehaviour { 7 8 Tree m_Tree; 9 Demo2Agent agent; 10 11 void Start () { 12 agent = new Demo2Agent (); 13 m_Tree = BLMyBehaveLibrary.InstantiateTree(BLMyBehaveLibrary.TreeType.NewCollection1_NewTree2, agent); 14 } 15 16 void Update () { 17 m_Tree.Tick(); 18 } 19 }
添加到场景就可以查看效果了。
Sequence
顺序节点会让连接它的子节点从左到右依次执行, 每个节点从底部的线决定了顺序,摆放的位置无关紧要,如果第一个子节点返回失败,则整个节点返回失败。如果该子节点返回成功,则会自动往右边一个子节点执行,如果该节点返回runing,则会重新开始运行。
我们创建一个新的行为树,如下:
我们新建一个Demo3Agent:
1 using Behave.Runtime; 2 using UnityEngine; 3 using System.Collections; 4 using Tree = Behave.Runtime.Tree; 5 6 public class Demo3Agent : IAgent { 7 8 public GameObject cube; 9 public float time; 10 11 float nowTime = 0; 12 13 public void Reset (Tree sender) { 14 15 } 16 17 public int SelectTopPriority (Tree sender, params int[] IDs) { 18 return 0; 19 } 20 21 public BehaveResult Tick (Tree sender, bool init) { 22 Debug.Log("调用系统的Tick方法"); 23 return BehaveResult.Success; 24 } 25 26 public BehaveResult TickMyAction1Action(Tree sender) { 27 Debug.Log("我的action1"); 28 if (cube.transform.position.x >= 3.0f) { 29 cube.transform.position = new Vector3(3.0f, 0, 0); 30 return BehaveResult.Success; 31 } 32 cube.transform.Translate(new Vector3(2.0f * time, 0, 0)); 33 return BehaveResult.Running; 34 } 35 36 public BehaveResult TickMyAction2Action(Tree sender) { 37 Debug.Log("我的action2"); 38 if (nowTime >= 1.0f) { 39 nowTime = 0; 40 cube.transform.localEulerAngles = new Vector3(0, 0, 0); 41 return BehaveResult.Success; 42 } 43 cube.transform.Rotate(new Vector3(360.0f * time, 0, 0)); 44 nowTime += time; 45 return BehaveResult.Running; 46 } 47 48 public BehaveResult TickMyAction3Action(Tree sender) { 49 Debug.Log("我的action3"); 50 if (cube.transform.position.x <= 0) { 51 cube.transform.position = new Vector3(0, 0, 0); 52 return BehaveResult.Success; 53 } 54 cube.transform.Translate(new Vector3(-2.0f * time, 0, 0)); 55 return BehaveResult.Running; 56 } 57 }
我们再创建一个Demo3:
1 using UnityEngine; 2 using System.Collections; 3 using Behave.Runtime; 4 using Tree = Behave.Runtime.Tree; 5 6 public class Demo3 : MonoBehaviour { 7 8 public GameObject cube; 9 10 Tree m_Tree; 11 Demo3Agent agent; 12 13 void Start () { 14 agent = new Demo3Agent (); 15 agent.cube = cube; 16 m_Tree = BLMyBehaveLibrary.InstantiateTree(BLMyBehaveLibrary.TreeType.NewCollection1_NewTree3, agent); 17 } 18 19 void Update () { 20 agent.time = Time.deltaTime; 21 m_Tree.Tick(); 22 } 23 }
我们在场景里添加一个Cube,把Demo3拖入并绑定Cube就可以查看效果了;
这里的效果是Cube先向前移动,然后旋转一下再向后移动,如此反复。
Selector
选择节点子节点会从左到右依次执行,和顺序节点不同的是,选择节点的子节点返回成功,则整个节点返回成功,如果子节点返回失败,则运行右边的一个子节点,并继续运行,一直到运行到子节点的末尾一个,则返回失败,下一次选择节点再被触发的时候,又从最左边 第一个节点开始运行。
我们创建一个新的行为树,如下:
我们新建一个Demo4Agent:
1 using Behave.Runtime; 2 using UnityEngine; 3 using System.Collections; 4 using Tree = Behave.Runtime.Tree; 5 6 public class Demo4Agent : IAgent { 7 8 public GameObject cube; 9 public float time; 10 11 float nowTime = 0; 12 13 public void Reset (Tree sender) { 14 15 } 16 17 public int SelectTopPriority (Tree sender, params int[] IDs) { 18 return 0; 19 } 20 21 public BehaveResult Tick (Tree sender, bool init) { 22 Debug.Log("调用系统的Tick方法"); 23 return BehaveResult.Success; 24 } 25 26 public BehaveResult TickMyAction1Action(Tree sender) { 27 Debug.Log("我的action1"); 28 if (nowTime >= 1.0f) { 29 nowTime = 0; 30 cube.transform.position = new Vector3(0, 0, 0); 31 //失败则执行下一个节点 32 if (Random.value > 0.5f) { 33 return BehaveResult.Failure; 34 } 35 return BehaveResult.Success; 36 } 37 cube.transform.Translate(new Vector3(2.0f * time, 0, 0)); 38 nowTime += time; 39 return BehaveResult.Running; 40 } 41 42 public BehaveResult TickMyAction2Action(Tree sender) { 43 Debug.Log("我的action2"); 44 if (nowTime >= 1.0f) { 45 nowTime = 0; 46 cube.transform.localEulerAngles = new Vector3(0, 0, 0); 47 //失败则执行下一个节点 48 if (Random.value > 0.5f) { 49 return BehaveResult.Failure; 50 } 51 return BehaveResult.Success; 52 } 53 cube.transform.Rotate(new Vector3(360.0f * time, 0, 0)); 54 nowTime += time; 55 return BehaveResult.Running; 56 } 57 58 public BehaveResult TickMyAction3Action(Tree sender) { 59 Debug.Log("我的action3"); 60 if (nowTime >= 1.0f) { 61 nowTime = 0; 62 cube.transform.localScale = new Vector3(1, 1, 1); 63 //失败则执行下一个节点 64 if (Random.value > 0.5f) { 65 return BehaveResult.Failure; 66 } 67 return BehaveResult.Success; 68 } 69 cube.transform.localScale = new Vector3(nowTime, nowTime, nowTime); 70 nowTime += time; 71 return BehaveResult.Running; 72 } 73 }
我们再创建一个Demo4:
1 using UnityEngine; 2 using System.Collections; 3 using Behave.Runtime; 4 using Tree = Behave.Runtime.Tree; 5 6 public class Demo4 : MonoBehaviour { 7 8 public GameObject cube; 9 10 Tree m_Tree; 11 Demo4Agent agent; 12 13 void Start () { 14 agent = new Demo4Agent (); 15 agent.cube = cube; 16 m_Tree = BLMyBehaveLibrary.InstantiateTree(BLMyBehaveLibrary.TreeType.NewCollection1_NewTree4, agent); 17 } 18 19 void Update () { 20 agent.time = Time.deltaTime; 21 m_Tree.Tick(); 22 } 23 }
我们的小正方形会先运行Action1,然后有50%的机会进入Action2,进入Action2后又有50%的机会进入Action3。
Parallel
并行节点会从左到右触发它所有的子节点工作,对于并行节点有两个重要的设置,一个是子节点完成,一个是组件完成,子节点完成参数决定了子节点的返回值该如何处理:
- 如果并行节点设置为成功或者失败,那么无论它返回的是成功还是失败,子节点的输出都标记为完成。
- 如果并行节点设置为成功,那么子节点的输出只在返回成功时候才标记为完成。在触发所有的子节点工作后,一个子节点返回失败就会让整个并行组件返回失败。
- 并行节点设置为失败的话也会同理,子节点只有在返回完成时,它才会返回失败。
我们创建一个新的行为树,如下:
选择并行节点可以看到属性:
这里的意思是:所有的子节点都返回成功则退出该节点。
我们新建一个Demo5Agent:
1 using Behave.Runtime; 2 using UnityEngine; 3 using System.Collections; 4 using Tree = Behave.Runtime.Tree; 5 6 public class Demo5Agent : IAgent { 7 8 public GameObject cube; 9 public float time; 10 11 float nowTime = 0; 12 13 public void Reset (Tree sender) { 14 15 } 16 17 public int SelectTopPriority (Tree sender, params int[] IDs) { 18 return 0; 19 } 20 21 public BehaveResult Tick (Tree sender, bool init) { 22 Debug.Log("调用系统的Tick方法"); 23 return BehaveResult.Success; 24 } 25 26 public BehaveResult TickMyAction1Action(Tree sender) { 27 Debug.Log("我的action1"); 28 if (cube.transform.position.x >= 3.0f) { 29 cube.transform.position = new Vector3(3.0f, 0, 0); 30 return BehaveResult.Success; 31 } 32 cube.transform.Translate(new Vector3(2.0f * time, 0, 0)); 33 return BehaveResult.Running; 34 } 35 36 public BehaveResult TickMyAction2Action(Tree sender) { 37 Debug.Log("我的action2"); 38 if (nowTime >= 1.0f) { 39 nowTime = 0; 40 cube.transform.localEulerAngles = new Vector3(0, 0, 0); 41 return BehaveResult.Success; 42 } 43 cube.transform.Rotate(new Vector3(360.0f * time, 0, 0)); 44 nowTime += time; 45 return BehaveResult.Running; 46 } 47 48 public BehaveResult TickMyAction3Action(Tree sender) { 49 Debug.Log("我的action3"); 50 if (cube.transform.position.x <= 0) { 51 cube.transform.position = new Vector3(0, 0, 0); 52 return BehaveResult.Success; 53 } 54 cube.transform.Translate(new Vector3(-2.0f * time, 0, 0)); 55 return BehaveResult.Running; 56 } 57 }
我们再创建一个Demo5:
1 using UnityEngine; 2 using System.Collections; 3 using Behave.Runtime; 4 using Tree = Behave.Runtime.Tree; 5 6 public class Demo5 : MonoBehaviour { 7 8 public GameObject cube; 9 10 Tree m_Tree; 11 Demo5Agent agent; 12 13 void Start () { 14 agent = new Demo5Agent (); 15 agent.cube = cube; 16 m_Tree = BLMyBehaveLibrary.InstantiateTree(BLMyBehaveLibrary.TreeType.NewCollection1_NewTree5, agent); 17 } 18 19 void Update () { 20 agent.time = Time.deltaTime; 21 m_Tree.Tick(); 22 } 23 }
运行游戏:会看见小正方形会旋转着前进,因为并行是所有子节点每帧都会被调用到,当两个子节点都返回成功时退出该节点。小正方形恢复到原点。