--- --- Generated by EmmyLua(https://github.com/EmmyLua) --- Created by xxn. --- DateTime: 2021/1/7 13:25 --- -- 行为树各类节点 --[[ 行为树节点主要分为: 1、组合节点(序列节点、选择节点、并行节点等) 2、装饰节点(且只能有一个子节点) 3、条件节点 4、动作节点 只有条件节点和动作节点能做完行为树的叶子节点, 而组合、装饰节点控制行为树的决策走向,所以, 条件和动作节点称为行为节点(Behavior Node), 组合和装饰节点称为决策节点(Decider Node)。 只有叶子节点才需要特别定制。 --]] -- 行为树节点父类 ---@class BehaviorNode BehaviorNode = class() ---@param children BehaviorNode[] function BehaviorNode:ctor(children) self.parent = nil self.kind = BehaviorNodeEnum.BehaviourNode --行为树节点种类 self.children = children --子节点列表(数组) self.owner = nil --行为树拥有者 self.status = BehaviorStatusEnum.READY --当前状态 self.lastResult = BehaviorStatusEnum.READY --上一次结果 if children then for _,child in ipairs(children) do child.parent = self end end end function BehaviorNode:SetOwner(owner) self.owner = owner if self.children then for k, child in ipairs(self.children) do child:SetOwner(owner) end end end function BehaviorNode:IsKindOf(k) return self.kind == k end function BehaviorNode:Visit() end -- 步进 -- 如果该处于运行中并且有子节点,则步进子节点; 否则,重置该节点以及子节点 function BehaviorNode:Step() if self.status ~= BehaviorStatusEnum.RUNNING then self:Reset() elseif self.children then for k, v in ipairs(self.children) do v:Step() end end end -- 重置节点为ready状态 function BehaviorNode:Reset() if self.status ~= BehaviorStatusEnum.READY then self.status = BehaviorStatusEnum.READY if self.children then for _, child in ipairs(self.children) do child:Reset() end end end end function BehaviorNode:Stop() if self.children then for _, child in ipairs(self.children) do child:Stop() end end end -- 保存上一次update的状态 function BehaviorNode:SaveStatus() self.lastResult = self.status if self.children then for k,v in ipairs(self.children) do v:SaveStatus() end end end ---@param nodeEnum BehaviorNodeEnum function BehaviorNode:FindNode(nodeEnum) if self.kind == nodeEnum then return self end if self.children then for k, v in pairs(self.children) do local f = v:FindNode(v) if f then return f end end end end ------------------------------------- 条件节点 ------------------------------------- --[[ 条件节点根据比较结果返回成功或失败,但永远不会返回正在执行(Running) --]] ---@class ConditionNode:BehaviorNode ConditionNode = class(BehaviorNode) function ConditionNode:ctor(func) BehaviorNode.ctor(self) self.kind = BehaviorNodeEnum.ConditionNode self.func = func end -- 条件为true则返回成功 function ConditionNode:Visit() if self.func and self.func() then self.status = BehaviorStatusEnum.SUCCESS else self.status = BehaviorStatusEnum.FAILED end end ------------------------------------- 动作节点 ------------------------------------- -- 通常对应owner的某个方法,一般是个瞬间动作,比如放个技能 ---@class ActionNode:BehaviorNode ActionNode = class(BehaviorNode) function ActionNode:ctor(action, resetFnc) BehaviorNode.ctor(self) self.kind = BehaviorNodeEnum.ActionNode self.action = action self.resetFnc = resetFnc end function ActionNode:Reset() BehaviorNode.Reset(self) if self.resetFnc then self.resetFnc() end end function ActionNode:Visit() if self.action then self.action() end self.status = BehaviorStatusEnum.SUCCESS end ------------------------------------- 组合节点 ------------------------------------- -- 序列节点 --[[ 它实现的是and的逻辑,例如:r = x and y and z,则先执行x,如果x为true,则继续执行y,如果x为false,则直接返回false,以此类推 执行该节点时,它会一个接一个运行, 如果子节点状态为success,则执行下一个子节点; 如果子节点状态为running,则把自身设置为running,并等待返回其他结果(success或failed); 如果子节点状态为failed,则把自身设置为failed,并返回; 如果所有节点都为success,则把自身设置为success并返回。 原则:只要一个子节点返回"失败"或"运行中",则返回;若返回"成功",则执行下一个子节点。 --]] ---@class SequenceNode:BehaviorNode SequenceNode = class(BehaviorNode) function SequenceNode:ctor(children) BehaviorNode.ctor(self, children) self.kind = BehaviorNodeEnum.SequenceNode self.index = 1 -- 运行的是第几个节点 end function SequenceNode:Reset() self.index = 1 BehaviorNode.Reset(self) end function SequenceNode:Visit() if self.status ~= BehaviorStatusEnum.RUNNING then --如果没有运行的子节点,则从头开始执行 self.index = 1 end local count = #self.children local child local status while self.index <= count do child = self.children[self.index] child:Visit() status = child.status if status == BehaviorStatusEnum.RUNNING or status == BehaviorStatusEnum.FAILED then self.status = status if BTMgr.IsDebug == true then if child.nodeName == nil then -- 这些是中间节点,非叶子节点 else logError(child.nodeName .. ' ' .. child.status) end end return end self.index = self.index + 1 end self.status = BehaviorStatusEnum.SUCCESS --所有子节点都返回success end -- 选择节点 --[[ 它实现的是or的逻辑,例如:r = x or y or z,则先执行x,如果x为false,则继续执行y,如果x为true,则直接返回true,以此类推 执行该节点时,它会一个接一个运行, 如果子节点状态为success,则把自身设置为success并返回; 如果子节点状态为running,则把自身设置为running,并等待返回其他结果(success或failed); 如果子节点状态为failed,则会执行下一个子节点; 如果所有没子节点都不为success,则把自身设置为failed并返回。 原则:只要一个子节点返回"成功"或"运行中",则返回;若返回"失败",则执行下一个子节点。 --]] ---@class SelectorNode:BehaviorNode SelectorNode = class(BehaviorNode) function SelectorNode:ctor(children) BehaviorNode.ctor(self, children) self.kind = BehaviorNodeEnum.SelectorNode self.index = 1 -- 运行的是第几个节点 end function SelectorNode:Reset() self.index = 1 BehaviorNode.Reset(self) end function SelectorNode:Visit() if self.status ~= BehaviorStatusEnum.RUNNING then --如果没有运行的子节点,则从头开始执行 self.index = 1 end local count = #self.children local child local status while self.index <= count do child = self.children[self.index] child:Visit() status = child.status if status == BehaviorStatusEnum.SUCCESS or status == BehaviorStatusEnum.RUNNING then self.status = status if BTMgr.IsDebug == true then if child.nodeName == nil then -- 这些是中间节点,非叶子节点 else logError(child.nodeName .. ' ' .. child.status) end end return end self.index = self.index + 1 end self.status = BehaviorStatusEnum.FAILED --所有子节点都返回failed end -- 并行节点 --[[ 看上去是同时执行所有的子节点,但是真正的逻辑还是一个一个执行子节点。 它实现的是and的逻辑,例如:r = x and y and z,则先执行x,如果x为true或者runing,则继续执行y,如果x为false,则直接返回false,以此类推 如果子节点的状态是failed,则将自身设置为failed,并返回; 如果子节点是success或者running,则运行下一个子节点; 如果所有子节点都为success,则将自身设置为success并返回,否则设置自身为running。 在运行到该节点时,要对部分节点(ConditionNode、NotDecorator)做重置,重启判断。 ps:这里的实现的其实是Parallel Sequence Node,如果子节点failed,则返回。 并行节点可以设置退出条件 和序列节点不同的是,序列节点子节点返回runing状态的时候就返回不执行后面的节点 并行节点是返回runing状态的时候就返回继续执行后面的节点 他们遇到子节点false时都返回,不执行后面的节点 --]] ---@class ParallelNode:BehaviorNode ParallelNode = class(BehaviorNode) function ParallelNode:ctor(children) BehaviorNode.ctor(self, children) self.kind = BehaviorNodeEnum.ParallelNode self.stopOnAnyComplete = nil end function ParallelNode:Step() if self.status ~= BehaviorStatusEnum.RUNNING then self:Reset() else --只重置条件子节点 if self.children then for i,child in ipairs(self.children) do if self:IsKindOf(BehaviorNodeEnum.ConditionNode) and child.status == BehaviorStatusEnum.SUCCESS then child:Reset() end end end end end function ParallelNode:Visit() local done = true --是否所有子节点都success local any_done = false for _, child in ipairs(self.children) do if child:IsKindOf(BehaviorNodeEnum.ConditionNode) then --重启条件节点 child:Reset() end if child.status ~= BehaviorStatusEnum.SUCCESS then child:Visit() if child.status == BehaviorStatusEnum.FAILED then self.status = BehaviorStatusEnum.FAILED return end end if child.status == BehaviorStatusEnum.RUNNING then done = false else -- success any_done = true end end if done or (self.stopOnAnyComplete and any_done) then self.status = BehaviorStatusEnum.SUCCESS else self.status = BehaviorStatusEnum.RUNNING end end --if 节点 --实现了if操作,只有cond为success时,node才会被执行 --注意:如果node处于运行中,则会在下一次思考时,继续执行node节点,直到node返回成功或失败,该节点才会退出 --如果node节点有可能出现运行中状态,则该节点不适用 ---@class IfNode:BehaviorNode IfNode = class(SequenceNode) function IfNode:ctor(condFunc, node) local children = {ConditionNode(condFunc),node} SequenceNode.ctor(self, children) self.kind = BehaviorNodeEnum.IfNode end ---status值由node或者elseNode决定,node和elseNode可以再套IfElseNode ---@class IfElseNode:BehaviorNode IfElseNode = class(BehaviorNode) ---@param node BehaviorNode ---@param elseNode BehaviorNode function IfElseNode:ctor(condFunc, node,elseNode) local children = {node,elseNode} BehaviorNode.ctor(self, children) self.kind = BehaviorNodeEnum.IfElseNode self.condFunc = condFunc self.node = node self.elseNode = elseNode self.runingNode = nil end function IfElseNode:Visit() if self.lastVisitNode then self.lastVisitNode:Visit() self.status = self.lastVisitNode.status if self.status ~= BehaviorStatusEnum.RUNNING then self.lastVisitNode = nil end return end if self.condFunc() then self.node:Visit() self.lastVisitNode = self.node self.status = self.node.status else self.elseNode:Visit() self.lastVisitNode = self.elseNode self.status = self.elseNode.status end if self.status ~= BehaviorStatusEnum.RUNNING then self.lastVisitNode = nil end end --- wait 节点 --等待条件达成继续运行 ---@class WaitNode : BehaviorNode WaitNode = class(BehaviorNode) ---@param waitFun function @等待判定方法 function WaitNode:ctor(waitFun) BehaviorNode.ctor(self, nil) self.waitFun = waitFun end function WaitNode:Reset() BehaviorNode.Reset(self) end function WaitNode:Visit() if not self.waitFun then self.status = BehaviorStatusEnum.SUCCESS return end if self.waitFun() then self.status = BehaviorStatusEnum.SUCCESS else self.status = BehaviorStatusEnum.RUNNING end end