Parallel节点类似Sequence节点,不同在于Parallel会每帧执行所有的节点。当所有节点返回成功时返回成功,当其中一个节点返回失败时,返回失败并且结束所有的子节点运行。
例如说,给Sequence节点插入一个不断返回Running的行为节点,那么就会造成后面的子节点无法执行,而对于Parallel来说,是不会存在这种阻塞情况的。
Parallel.cs
1 namespace BehaviorDesigner.Runtime.Tasks 2 { 3 [TaskDescription("Similar to the sequence task, the parallel task will run each child task until a child task returns failure. " + 4 "The difference is that the parallel task will run all of its children tasks simultaneously versus running each task one at a time. " + 5 "Like the sequence class, the parallel task will return success once all of its children tasks have return success. " + 6 "If one tasks returns failure the parallel task will end all of the child tasks and return failure.")] 7 [HelpURL("http://www.opsive.com/assets/BehaviorDesigner/documentation.php?id=27")] 8 [TaskIcon("{SkinColor}ParallelIcon.png")] 9 public class Parallel : Composite 10 { 11 // The index of the child that is currently running or is about to run. 12 private int currentChildIndex; 13 // The task status of every child task. 14 private TaskStatus[] executionStatus; 15 16 public override void OnAwake() 17 { 18 // Create a new task status array that will hold the execution status of all of the children tasks. 19 executionStatus = new TaskStatus[children.Count]; 20 } 21 22 public override void OnChildStarted(int childIndex) 23 { 24 // One of the children has started to run. Increment the child index and set the current task status of that child to running. 25 currentChildIndex++; 26 executionStatus[childIndex] = TaskStatus.Running; 27 } 28 29 public override bool CanRunParallelChildren() 30 { 31 // This task can run parallel children. 32 return true; 33 } 34 35 public override int CurrentChildIndex() 36 { 37 return currentChildIndex; 38 } 39 40 public override bool CanExecute() 41 { 42 // We can continue executing if we have more children that haven't been started yet. 43 return currentChildIndex < children.Count; 44 } 45 46 public override void OnChildExecuted(int childIndex, TaskStatus childStatus) 47 { 48 // One of the children has finished running. Set the task status. 49 executionStatus[childIndex] = childStatus; 50 } 51 52 public override TaskStatus OverrideStatus(TaskStatus status) 53 { 54 // Assume all of the children have finished executing. Loop through the execution status of every child and check to see if any tasks are currently running 55 // or failed. If a task is still running then all of the children are not done executing and the parallel task should continue to return a task status of running. 56 // If a task failed then return failure. The Behavior Manager will stop all of the children tasks. If no child task is running or has failed then the parallel 57 // task succeeded and it will return success. 58 bool childrenComplete = true; 59 for (int i = 0; i < executionStatus.Length; ++i) { 60 if (executionStatus[i] == TaskStatus.Running) { 61 childrenComplete = false; 62 } else if (executionStatus[i] == TaskStatus.Failure) { 63 return TaskStatus.Failure; 64 } 65 } 66 return (childrenComplete ? TaskStatus.Success : TaskStatus.Running); 67 } 68 69 public override void OnConditionalAbort(int childIndex) 70 { 71 // Start from the beginning on an abort 72 currentChildIndex = 0; 73 for (int i = 0; i < executionStatus.Length; ++i) { 74 executionStatus[i] = TaskStatus.Inactive; 75 } 76 } 77 78 public override void OnEnd() 79 { 80 // Reset the execution status and the child index back to their starting values. 81 for (int i = 0; i < executionStatus.Length; ++i) { 82 executionStatus[i] = TaskStatus.Inactive; 83 } 84 currentChildIndex = 0; 85 } 86 } 87 }
BTParallel.lua
1 BTParallel = BTComposite:New(); 2 3 local this = BTParallel; 4 this.name = "BTParallel"; 5 6 function this:New() 7 local o = {}; 8 setmetatable(o, self); 9 self.__index = self; 10 o.childTasks = {}; 11 o.executionStatus = {}; 12 return o; 13 end 14 15 function this:OnUpdate() 16 if (not self:HasChild()) then 17 return BTTaskStatus.Failure; 18 end 19 20 for i=1,#self.childTasks do 21 local childTask = self.childTasks[i]; 22 if (not self.executionStatus[i]) then --第一次执行 23 self.executionStatus[i] = childTask:OnUpdate(); 24 if (self.executionStatus[i] == BTTaskStatus.Failure) then 25 return BTTaskStatus.Failure; 26 end 27 elseif (self.executionStatus[i] == BTTaskStatus.Running) then --第二次以及以后执行 28 self.executionStatus[i] = childTask:OnUpdate(); 29 if (self.executionStatus[i] == BTTaskStatus.Failure) then 30 return BTTaskStatus.Failure; 31 end 32 end 33 end 34 35 local childrenComplete = true; 36 for i=1,#self.executionStatus do 37 if (self.executionStatus[i] == BTTaskStatus.Running) then 38 childrenComplete = false; 39 break; 40 end 41 end 42 if (childrenComplete) then 43 return BTTaskStatus.Success; 44 else 45 return BTTaskStatus.Running; 46 end 47 end
测试如下:
1.BTSequence和BTParallel的对比
BTSequence:
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 sequence = BTSequence:New(); 16 local action = self:GetBTActionUniversal(); 17 local log = BTLog:New("This is log!!!"); 18 log.name = "log"; 19 20 self:SetStartTask(sequence); 21 22 sequence:AddChild(action); 23 sequence:AddChild(log); 24 end 25 26 function this:GetBTActionUniversal() 27 local count = 1; 28 local a = function () 29 if (count <= 3) then 30 count = count + 1; 31 print("22"); 32 return BTTaskStatus.Running; 33 else 34 return BTTaskStatus.Success; 35 end 36 end 37 local universal = BTActionUniversal:New(nil, a); 38 return universal; 39 end
BTParallel:
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 log = BTLog:New("This is log!!!"); 18 log.name = "log"; 19 20 self:SetStartTask(parallel); 21 22 parallel:AddChild(action); 23 parallel:AddChild(log); 24 end 25 26 function this:GetBTActionUniversal() 27 local count = 1; 28 local a = function () 29 if (count <= 3) then 30 count = count + 1; 31 print("22"); 32 return BTTaskStatus.Running; 33 else 34 return BTTaskStatus.Success; 35 end 36 end 37 local universal = BTActionUniversal:New(nil, a); 38 return universal; 39 end
2.BTParallel中返回失败中断执行的情况
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.Failure; 43 end); 44 return universal; 45 end