[Unity插件]Lua行为树(三):组合节点Sequence
Sequence的继承关系如下:
Sequence->Composite->ParentTask->Task
上一篇已经实现了简单版本的ParentTask和Task(基于Behavior Designer的源码),那么接下来看下Composite和Sequence。
1.Composite:表明该节点是组合节点,无特殊作用。
2.Sequence:
成员:
currentChildIndex:当前运行的子节点索引
executionStatus:当前运行的子节点状态
方法:
CanExecute:当有可运行的子节点并且子节点不返回失败时,返回true
OnChildExecuted:当一个子节点运行完后调用,将当前索引指向下一个节点,同时更新当前运行的子节点状态
OnEnd:Sequence运行结束时调用,重置变量
namespace BehaviorDesigner.Runtime.Tasks
{
[TaskDescription("The sequence task is similar to an \"and\" operation. It will return failure as soon as one of its child tasks return failure. " +
"If a child task returns success then it will sequentially run the next task. If all child tasks return success then it will return success.")]
[HelpURL("http://www.opsive.com/assets/BehaviorDesigner/documentation.php?id=25")]
[TaskIcon("{SkinColor}SequenceIcon.png")]
public class Sequence : Composite
{
// The index of the child that is currently running or is about to run.
private int currentChildIndex = ;
// The task status of the last child ran.
private TaskStatus executionStatus = TaskStatus.Inactive; public override int CurrentChildIndex()
{
return currentChildIndex;
} public override bool CanExecute()
{
// We can continue to execuate as long as we have children that haven't been executed and no child has returned failure.
return currentChildIndex < children.Count && executionStatus != TaskStatus.Failure;
} public override void OnChildExecuted(TaskStatus childStatus)
{
// Increase the child index and update the execution status after a child has finished running.
currentChildIndex++;
executionStatus = childStatus;
} public override void OnConditionalAbort(int childIndex)
{
// Set the current child index to the index that caused the abort
currentChildIndex = childIndex;
executionStatus = TaskStatus.Inactive;
} public override void OnEnd()
{
// All of the children have run. Reset the variables back to their starting values.
executionStatus = TaskStatus.Inactive;
currentChildIndex = ;
}
}
}
当然,因为Behavior Designer源码的代码量比较多,所以不可能完全地实现一个Lua版本的BD,不过可以参考里面的一些设计思想去实现一套行为树。
以Sequence节点为例:
1.如果当前节点返回Failure,则Sequence返回Failure,结束执行Sequence
2.如果当前节点返回Running,则Sequence返回Running,下一帧继续执行当前节点
3.如果当前节点返回Success,那么Sequence将会执行下一个节点,这里会出现两种做法,一是Sequence返回Running,等下一帧再执行下一节点;二是在同一帧下继续执行。这里我采用的是第二种,因为在早期的AI中,逻辑都是在Update中进行的,也就是逻辑都在同一帧中,因此我觉得放在同一帧中执行效率会高一些。

代码如下:
BTParentTask.lua
BTParentTask = BTTask:New(); local this = BTParentTask; function this:New()
local o = {};
setmetatable(o, self);
self.__index = self;
o.currentChildIndex = ; --当前运行到第几个子节点
o.currentChildTask = nil; --当前运行的子节点
o.childTasks = {}; --子节点列表
return o;
end function this:AddChild(task)
local index = #self.childTasks + ;
task.index = index;
task.layer = self.layer + ;
task.parent = self;
task.root = self.root;
self.childTasks[index] = task;
end --是否有子节点
function this:HasChild()
if (#self.childTasks > ) then
return true;
else
return false;
end
end --获取下一个要执行的子节点
function this:GetNextChild()
if (#self.childTasks >= (self.currentChildIndex + )) then
self.currentChildIndex = self.currentChildIndex + ;
return self.childTasks[self.currentChildIndex];
end
return nil;
end --重置
function this:Reset()
self.currentChildIndex = ;
self.currentChildTask = nil;
end
BTSequence.lua
BTSequence = BTComposite:New(); local this = BTSequence; function this:New()
local o = {};
setmetatable(o, self);
self.__index = self;
o.executionStatus = BTTaskStatus.Inactive;
return o;
end function this:OnUpdate()
if (not self:HasChild()) then
return BTTaskStatus.Failure;
end if (not self.currentChildTask) then
self.currentChildTask = self:GetNextChild();
if (not self.currentChildTask) then
return BTTaskStatus.Failure;
end
end while (self.currentChildTask) do
self.executionStatus = self.currentChildTask:OnUpdate();
if (self.executionStatus == BTTaskStatus.Failure) then --结束
self:Reset();
return BTTaskStatus.Failure;
elseif (self.executionStatus == BTTaskStatus.Running) then --下一帧继续执行
return BTTaskStatus.Running;
else --继续执行下一节点
self.currentChildTask = self:GetNextChild();
end
end --所有节点执行完毕
self.executionStatus = BTTaskStatus.Success;
self:Reset();
return BTTaskStatus.Success;
end
TestBehaviorTree.lua
TestBehaviorTree = BTBehaviorTree:New(); local this = TestBehaviorTree; function this:New()
local o = {};
setmetatable(o, self);
self.__index = self;
this:Init();
return o;
end function this:Init()
local sequence = BTSequence:New();
local log = BTLog:New("hello world!");
local log2 = BTLog:New("This is a test");
sequence:AddChild(log);
sequence:AddChild(log2);
this:PushTask(sequence);
end
打印如下:

[Unity插件]Lua行为树(三):组合节点Sequence的更多相关文章
- [Unity插件]Lua行为树(十三):装饰节点完善
之前介绍了组合节点中三大常用的节点:BTSequence.BTSelector和BTParallel,一般来说,这三种就够用了,可以满足很多的需求. 接下来可以完善一下装饰节点,增加几种新的节点. 1 ...
- [Unity插件]Lua行为树(七):行为树嵌套
在上一篇的基础上,可以测试下行为树的嵌套,所谓的行为树嵌套,就是在一棵行为树下的某一个分支,接入另一棵行为树. 以下面这棵行为树为例: TestBehaviorTree2.lua TestBehavi ...
- [Unity插件]Lua行为树(六):打印树结构
经过前面的文章,已经把行为树中的四种基本类型节点介绍了下.接下来可以整理一下,打印一下整棵行为树.注意点如下: 1.可以把BTBehaviorTree也当作一种节点,这样就可以方便地进行行为树嵌套了 ...
- [Unity插件]Lua行为树(二):树结构
参考链接:https://blog.csdn.net/u012740992/article/details/79366251 在行为树中,有四种最基本的节点,其继承结构如下: Action->T ...
- [Unity插件]Lua行为树(十一):组合节点Parallel
Parallel节点类似Sequence节点,不同在于Parallel会每帧执行所有的节点.当所有节点返回成功时返回成功,当其中一个节点返回失败时,返回失败并且结束所有的子节点运行. 例如说,给Seq ...
- [Unity插件]Lua行为树(五):装饰节点Repeater
Repeater:重复执行子节点,直到一定次数 特点如下: 1.执行次数可以是无限循环,也可以是固定次数 2.一般来说,子节点的执行返回状态不会影响Repeater节点,但可以设置当子节点返回失败时, ...
- [Unity插件]Lua行为树(四):条件节点和行为节点
条件节点和行为节点,这两种节点本身的设计比较简单,项目中编写行为树节点一般就是扩展这两种节点,而Decorator和Composite节点只需要使用内置的就足够了. 它们的继承关系如下: Condit ...
- [Unity插件]Lua行为树(十):通用行为和通用条件节点
在行为树中,需要扩展的主要是行为节点和条件节点.一般来说,每当要创建一个节点时,就要新建一个节点文件.而对于一些简单的行为节点和条件节点,为了去掉新建文件的过程,可以写一个通用版本的行为节点和条件节点 ...
- [Unity插件]Lua行为树(九):条件节点调整
先看一下之前的条件节点是怎么设计的: BTConditional.lua BTConditional = BTTask:New(); local this = BTConditional; this. ...
随机推荐
- Qt 中的事件处理(二)
1. 回顾事件传递的过程 ①源头:操作系统 操作系统检测到用户的动作时,就会产生一个系统消息,系统消息就会被发送到正在运行的Qt应用程序中, ②应用程序收到系统消息后, 他会将系统消息翻译成对应的 ...
- MySQL 5.7 Invalid default value for 'CREATE_TIME'报错的解决方法
出处:http://blog.itpub.net/15498/viewspace-2136006/ 由于数据库的升级,今天在执行从MySQL 5.6导出来的SQL文件时报错: mysql> so ...
- 运动目标检测中基于HSV空间的阴影去除算法
在运动目标检测中,常常会出现由于光线被遮挡,或场景其他物体的遮挡,在目标附近或场景里出现阴影,阴影的出现对后期目标的正确分割与处理带了很大的不便.如今,国内外已有不少文献来研究这个问题,并且提出了各种 ...
- ubuntu-docker入门到放弃(四)容器的导入导出
上一次我们讲了如何搭建自己私有的镜像管理仓库,实际上我们使用的依然是别人或者公共的image,今天就来说说如何将自己定制化的images上传到自己的私有仓库中,以供符合自己业务场景的项目来使用,如:我 ...
- WCF 基础连接已经关闭: 服务器关闭了本应保持活动状态的连接。
详细错误信息: System.ServiceModel.CommunicationException: 接收对 http://localhost:48655/XXXXXX.svc 的 HTTP 响应时 ...
- Docker-compose ports和expose的区别
docker-compose中有两种方式可以暴露容器的端口:ports和expose. 1 ports ports暴露容器端口到主机的任意端口或指定端口,用法: ports: - "80:8 ...
- NetBeans IDE 多行标签设置方法
- Boost--variant (C++中的union)
union联合体类型的问题 只能用于内部类型,这使得union在C++中几乎没有用 所以boost提供了variant,相当于是C++中的union #include "boost/vari ...
- C++进阶--命名空间和关键字using
//############################################################################ /* * C++关键字:using * * ...
- C# name scheme
1.For varibale.camel scheme.the first word lowercase the first letter,then other words capitalize th ...