[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. ...
随机推荐
- R3注入的四种方式
DLL注入 1.首先要获取想要注入的进程句柄(OpenProcess) 2.从要注入的进程的地址空间中分配一段内存(VirtualAllocEx) 3.往分配的内存位置写入要注入的DLL名称(Writ ...
- RedHat7.3安装MySQL5.7
1.下载Mysql安装包 https://cdn.mysql.com//Downloads/MySQL-5.7/mysql-5.7.20-1.el6.x86_64.rpm-bundle.tar 附百度 ...
- 转:区块链开发(一)搭建基于以太坊go-ethereum的私有链环境
区块链开发(一)搭建基于以太坊go-ethereum的私有链环境 wo541075754 · 2016-11-07 13:00:03 · 3730 次点击 · 预计阅读时间 3 分钟 · 约1小时前 ...
- 学习java字符串编码总结
http://blog.csdn.net/wikijava/article/details/5571953 系统不同部分的编码方式转换
- Hadoop概念学习系列之Hadoop新手学习指导之入门需知(二十)
不多说,直接上干货! 零基础学习hadoop,没有想象的那么困难,也没有想象的那么容易.从一开始什么都不懂,到能够搭建集群,开发.整个过程,只要有Linux基础,虚拟机化和java基础,其实hadoo ...
- offse家族属性
在JavaScript中,常用offset.scroll和client家族属性来表示元素的位置和大小相关属性,最近在网上找到了一张图来表示三者之间的关系,正好可以在此借鉴一下. 本次主要来看一下off ...
- 云区域(region),可用区(AZ),跨区域数据复制(Cross-region replication)与灾备(Disaster Recovery)(部分1)
本文分两部分:部分1 和 部分2.部分1 介绍 AWS,部分2 介绍阿里云和OpenStack云. 1. AWS 1.1 AWS 地理组件概况 AWS 提供三种地理性组件: Regions:区域,即A ...
- Ajax的兼容及Ajax的缓存问题
Ajax的兼容: 在ie 6 7 8 不支持XMLHttpRequest的对象: 他的Ajax内置对象为ActiveXObject("Microsoft XMLHTTP") 除了内 ...
- 描述wxWidgets中事件处理的类型转化
wxWidgets是一个比较常用的UI界面库,我曾经试着使用wxWidgets写一个UI编辑工具,在此期间,学习了一些wxWidgets的知识.我对wxWidgets的绑定(Bind)比较好奇,想知道 ...
- ueditor 正在读取目录及网络链接错误
环境 ueditor1_3_5-gbk-net .NET版本3.5 如果把项目直接改成4.0不会出现这样的问题,查看 问题1:正在读取目录 找到ueditor/ueditor.config.js 找 ...