在上一篇的基础上,可以测试下行为树的嵌套,所谓的行为树嵌套,就是在一棵行为树下的某一个分支,接入另一棵行为树。
以下面这棵行为树为例:
TestBehaviorTree2.lua
1 TestBehaviorTree2 = BTBehaviorTree:New(); 2 3 local this = TestBehaviorTree2; 4 this.name = "TestBehaviorTree2"; 5 6 function this:New() 7 local o = {}; 8 setmetatable(o, self); 9 self.__index = self; 10 self:Init(); 11 return o; 12 end 13 14 function this:Init() 15 local repeater = BTRepeater:New(2); 16 local sequence = BTSequence:New(); 17 local log = BTLog:New("This is a other tree!!!"); 18 local log2 = BTLog:New("This is a other tree 2!!!"); 19 20 self:SetStartTask(repeater); 21 22 repeater:AddChild(sequence); 23 24 sequence:AddChild(log); 25 sequence:AddChild(log2); 26 end
TestBehaviorTree.lua
1 TestBehaviorTree = BTBehaviorTree:New(); 2 3 local this = TestBehaviorTree; 4 this.name = "TestBehaviorTree"; 5 6 function this:New() 7 local o = {}; 8 setmetatable(o, self); 9 self.__index = self; 10 self:Init(); 11 return o; 12 end 13 14 function this:Init() 15 local repeater = BTRepeater:New(2); 16 local selector = BTSelector:New(); 17 local sequence = BTSequence:New(); 18 local isNullOrEmpty = BTIsNullOrEmpty:New("123"); 19 local log = BTLog:New("This is a empty string!!!"); 20 local tree2 = TestBehaviorTree2:New(); 21 22 self:SetStartTask(repeater); 23 24 repeater:AddChild(selector); 25 26 selector:AddChild(sequence); 27 selector:AddChild(tree2); 28 29 sequence:AddChild(isNullOrEmpty); 30 sequence:AddChild(log); 31 end
打印如下:
上面的执行结果是没有问题的,由此可见,将BTBehaviorTree当作节点,然后嵌套在行为树中是可行的。不过通过上面的打印,可以发现嵌套树先被打印,然后总树才被打印,而且嵌套树的层级也是不对的。
对于打印错误,这是节点添加顺序造成的问题,因此不应该在设置节点或者添加节点时进行打印,应该在整棵数构成完成后进行打印。
对于层级不对,可以在添加嵌套树后更新嵌套树下的节点层级。
Enum.lua
1 --节点状态 2 BTTaskStatus = { 3 Inactive = 1, --尚未执行 4 Failure = 2, --返回失败 5 Success = 3, --返回成功 6 Running = 4, --执行中 7 } 8 9 --节点类型 10 BTTaskType = { 11 Root = 0, 12 Action = 1, 13 Composite = 2, 14 Conditional = 3, 15 Decorator = 4, 16 }
BTBehaviorManager.lua
1 BTBehaviorManager = {}; 2 3 local this = BTBehaviorManager; 4 this.printTreeStr = ""; 5 6 function this.RunTree(tree) 7 this.bTree = tree; 8 this.OnUpdate(); 9 end 10 11 function this.OnUpdate() 12 local status = this.bTree:OnUpdate(); 13 while (status == BTTaskStatus.Running) do 14 status = this.bTree:OnUpdate(); 15 end 16 end 17 18 --深度优先,打印树结构 19 function this.PrintTree(task) 20 this.printTreeStr = ""; 21 this.AddToPrintTreeStr(task); 22 print(this.printTreeStr); 23 end 24 25 function this.AddToPrintTreeStr(task) 26 local taskType = task.taskType; 27 28 this.printTreeStr = this.printTreeStr .. task:ToString() .. "\n"; 29 30 if (taskType == BTTaskType.Root) then 31 this.AddToPrintTreeStr(task.startTask); 32 elseif (taskType == BTTaskType.Composite or taskType == BTTaskType.Decorator) then 33 for i=1,#task.childTasks do 34 this.AddToPrintTreeStr(task.childTasks[i]); 35 end 36 else 37 38 end 39 end
BTBehaviorTree.lua
1 --[[ 2 树的根节点 3 --]] 4 BTBehaviorTree = BTTask:New(); 5 6 local this = BTBehaviorTree; 7 this.taskType = BTTaskType.Root; 8 9 function this:New() 10 local o = {}; 11 setmetatable(o, self); 12 self.__index = self; 13 return o; 14 end 15 16 --设置起始节点 17 function this:SetStartTask(task) 18 task.root = self; 19 task.parent = self; 20 task.layer = self.layer + 1; 21 self.startTask = task; 22 end 23 24 --更新子节点层级 25 function this:UpdateLayer() 26 self:UpdateChildLayer(self.startTask); 27 end 28 29 function this:UpdateChildLayer(task) 30 local taskType = task.taskType; 31 task.layer = task.root.layer + task.layer - 1; 32 33 if (taskType == BTTaskType.Root) then 34 self:UpdateChildLayer(task.startTask); 35 elseif (taskType == BTTaskType.Composite or taskType == BTTaskType.Decorator) then 36 for i=1,#task.childTasks do 37 self:UpdateChildLayer(task.childTasks[i]); 38 end 39 else 40 41 end 42 end 43 44 function this:OnUpdate() 45 if (self.startTask) then 46 return self.startTask:OnUpdate(); 47 end 48 end
打印如下: