[Unity插件]Lua行为树(十二):行为树管理

之前运行的行为树,都是一颗总树,那么实际上会有很多的总树,因此需要对行为树进行管理。

BTBehaviorManager.lua

 1 BTBehaviorManager = {};
 2 
 3 local this = BTBehaviorManager;
 4 this.isEachFrameCall = false;--是否是每帧调用
 5 this.printTreeStr = "";
 6 this.trees = {};
 7 
 8 function this.RunTree()
 9     if (isEachFrameCall) then
10     else
11         while (true) do
12             local isAllFinish = this.OnUpdate();
13             if (isAllFinish) then
14                 break;
15             end
16         end
17     end
18 end
19 
20 function this.OnUpdate()
21     local count = 0;
22 
23     for i=1,#this.trees do
24         local tree = this.trees[i];
25         if (tree.executionStatus == BTTaskStatus.Inactive) then --第一次执行
26             print("第一次执行:" .. tree.name);
27             tree:OnUpdate();
28         elseif (tree.executionStatus == BTTaskStatus.Running) then --第二次以及以后执行
29             print("第二次以及以后执行:" .. tree.name);
30             tree:OnUpdate();
31         else
32             count = count + 1;
33         end
34     end
35 
36     if (count == #this.trees) then
37         return true;
38     else
39         return false;         
40     end
41 end
42 
43 --添加行为树
44 function this.AddTree(task)
45     table.insert(this.trees, task);
46 end
47 
48 --深度优先,打印树结构
49 function this.PrintTree(task)
50     this.printTreeStr = "";
51     this.AddToPrintTreeStr(task);
52     print(this.printTreeStr);
53 end
54 
55 function this.AddToPrintTreeStr(task)
56     local taskType = task.taskType;
57     
58     this.printTreeStr = this.printTreeStr .. task:ToString() .. "
";
59 
60     if (taskType == BTTaskType.Root) then    
61         this.AddToPrintTreeStr(task.startTask);
62     elseif (taskType == BTTaskType.Composite or taskType == BTTaskType.Decorator) then
63         for i=1,#task.childTasks do
64             this.AddToPrintTreeStr(task.childTasks[i]);
65         end
66     else
67         
68     end
69 end

说明:

1.因为是运行在Sublime环境下的,所以这里使用while循环模拟每帧调用

2.关于AddTree和OnUpdate是否会冲突的问题。AddTree会增加trees的长度,但是在lua中for的三个表达式在循环开始前一次性求值,以后不再进行求值。比如#this.trees这个表达式只会在循环开始前执行一次,其结果用在后面的循环中。也就是说,如果在for循环过程中执行了AddTree方法,新增的元素会添加在后面,不会影响for循环的。

测试:

1.多行为树执行

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     o:Init();
11     return o;
12 end
13 
14 function this:Init()
15     local parallel = BTParallel:New();
16     local action = self:GetBTActionUniversal();
17     local action2 = self:GetBTActionUniversal2();
18 
19     self:SetStartTask(parallel);
20 
21     parallel:AddChild(action);
22     parallel:AddChild(action2);
23 end
24 
25 function this:GetBTActionUniversal()
26     local count = 1;
27     local a = function ()
28         if (count <= 3) then
29             count = count + 1;
30             print("22");
31             return BTTaskStatus.Running;
32         else
33             return BTTaskStatus.Success;
34         end
35     end
36     local universal = BTActionUniversal:New(nil, a);
37     return universal;
38 end
39 
40 function this:GetBTActionUniversal2()
41     local universal = BTActionUniversal:New(nil, function ()
42         return BTTaskStatus.Success;
43     end);
44     return universal;
45 end

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     o: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

TestMain.lua

 1 require "BehaviorTree/Core/Init"
 2 require "BehaviorTree/Test/TestBehaviorTree"
 3 require "BehaviorTree/Test/TestBehaviorTree2"
 4 
 5 local tree = TestBehaviorTree:New();
 6 local tree2 = TestBehaviorTree2:New();
 7 tree.name = "tree";
 8 tree2.name = "tree2";
 9 BTBehaviorManager.AddTree(tree);
10 BTBehaviorManager.AddTree(tree2);
11 BTBehaviorManager.RunTree();

输出如下:

2.for循环中添加行为树

TestBehaviorTree3.lua

 1 TestBehaviorTree3 = BTBehaviorTree:New();
 2 
 3 local this = TestBehaviorTree3;
 4 this.name = "TestBehaviorTree3";
 5 
 6 function this:New()
 7     local o = {};
 8     setmetatable(o, self);
 9     self.__index = self;
10     o:Init();
11     return o;
12 end
13 
14 function this:Init()
15     local repeater = BTRepeater:New(2);
16     local log = BTLog:New("This is TestBehaviorTree3 tree!!!");
17 
18     self:SetStartTask(repeater);
19 
20     repeater:AddChild(log);
21 end

BTBehaviorManager.lua

 1 BTBehaviorManager = {};
 2 
 3 local this = BTBehaviorManager;
 4 this.isEachFrameCall = false;--是否是每帧调用
 5 this.printTreeStr = "";
 6 this.trees = {};
 7 
 8 function this.RunTree()
 9     if (isEachFrameCall) then
10     else
11         while (true) do
12             local isAllFinish = this.OnUpdate();
13             if (isAllFinish) then
14                 break;
15             end
16         end
17     end
18 end
19 
20 local temp = false;
21 
22 function this.OnUpdate()
23     local count = 0;
24 
25     for i=1,#this.trees do
26         if (not temp) then
27             temp = true;
28             require "BehaviorTree/Test/TestBehaviorTree3"
29             local tree3 = TestBehaviorTree3:New();
30             tree3.name = "tree3";
31             this.AddTree(tree3);
32         end
33 
34         local tree = this.trees[i];
35         if (tree.executionStatus == BTTaskStatus.Inactive) then --第一次执行
36             print("第一次执行:" .. tree.name);
37             tree:OnUpdate();
38         elseif (tree.executionStatus == BTTaskStatus.Running) then --第二次以及以后执行
39             print("第二次以及以后执行:" .. tree.name);
40             tree:OnUpdate();
41         else
42             count = count + 1;
43         end
44     end
45 
46     print("------------------------------");
47 
48     if (count == #this.trees) then
49         return true;
50     else
51         return false;         
52     end
53 end
54 
55 --添加行为树
56 function this.AddTree(task)
57     table.insert(this.trees, task);
58 end
59 
60 --深度优先,打印树结构
61 function this.PrintTree(task)
62     this.printTreeStr = "";
63     this.AddToPrintTreeStr(task);
64     print(this.printTreeStr);
65 end
66 
67 function this.AddToPrintTreeStr(task)
68     local taskType = task.taskType;
69     
70     this.printTreeStr = this.printTreeStr .. task:ToString() .. "
";
71 
72     if (taskType == BTTaskType.Root) then    
73         this.AddToPrintTreeStr(task.startTask);
74     elseif (taskType == BTTaskType.Composite or taskType == BTTaskType.Decorator) then
75         for i=1,#task.childTasks do
76             this.AddToPrintTreeStr(task.childTasks[i]);
77         end
78     else
79         
80     end
81 end

输出如下。可以看到,在第一帧时,添加了行为树tree3,但是并不影响tree和tree2的执行,而在第二帧以及以后的帧时,tree3也开始执行了。

原文地址:https://www.cnblogs.com/lyh916/p/9689607.html