diff options
Diffstat (limited to 'Client/Assets/Behavior Designer/Runtime/Composites')
16 files changed, 727 insertions, 0 deletions
diff --git a/Client/Assets/Behavior Designer/Runtime/Composites/Parallel.cs b/Client/Assets/Behavior Designer/Runtime/Composites/Parallel.cs new file mode 100644 index 00000000..79969d26 --- /dev/null +++ b/Client/Assets/Behavior Designer/Runtime/Composites/Parallel.cs @@ -0,0 +1,87 @@ +namespace BehaviorDesigner.Runtime.Tasks
+{
+ [TaskDescription("Similar to the sequence task, the parallel task will run each child task until a child task returns failure. " +
+ "The difference is that the parallel task will run all of its children tasks simultaneously versus running each task one at a time. " +
+ "Like the sequence class, the parallel task will return success once all of its children tasks have return success. " +
+ "If one tasks returns failure the parallel task will end all of the child tasks and return failure.")]
+ [HelpURL("http://www.opsive.com/assets/BehaviorDesigner/documentation.php?id=27")]
+ [TaskIcon("{SkinColor}ParallelIcon.png")]
+ public class Parallel : Composite
+ {
+ // The index of the child that is currently running or is about to run.
+ private int currentChildIndex;
+ // The task status of every child task.
+ private TaskStatus[] executionStatus;
+
+ public override void OnAwake()
+ {
+ // Create a new task status array that will hold the execution status of all of the children tasks.
+ executionStatus = new TaskStatus[children.Count];
+ }
+
+ public override void OnChildStarted(int childIndex)
+ {
+ // One of the children has started to run. Increment the child index and set the current task status of that child to running.
+ currentChildIndex++;
+ executionStatus[childIndex] = TaskStatus.Running;
+ }
+
+ public override bool CanRunParallelChildren()
+ {
+ // This task can run parallel children.
+ return true;
+ }
+
+ public override int CurrentChildIndex()
+ {
+ return currentChildIndex;
+ }
+
+ public override bool CanExecute()
+ {
+ // We can continue executing if we have more children that haven't been started yet.
+ return currentChildIndex < children.Count;
+ }
+
+ public override void OnChildExecuted(int childIndex, TaskStatus childStatus)
+ {
+ // One of the children has finished running. Set the task status.
+ executionStatus[childIndex] = childStatus;
+ }
+
+ public override TaskStatus OverrideStatus(TaskStatus status)
+ {
+ // 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
+ // 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.
+ // 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
+ // task succeeded and it will return success.
+ bool childrenComplete = true;
+ for (int i = 0; i < executionStatus.Length; ++i) {
+ if (executionStatus[i] == TaskStatus.Running) {
+ childrenComplete = false;
+ } else if (executionStatus[i] == TaskStatus.Failure) {
+ return TaskStatus.Failure;
+ }
+ }
+ return (childrenComplete ? TaskStatus.Success : TaskStatus.Running);
+ }
+
+ public override void OnConditionalAbort(int childIndex)
+ {
+ // Start from the beginning on an abort
+ currentChildIndex = 0;
+ for (int i = 0; i < executionStatus.Length; ++i) {
+ executionStatus[i] = TaskStatus.Inactive;
+ }
+ }
+
+ public override void OnEnd()
+ {
+ // Reset the execution status and the child index back to their starting values.
+ for (int i = 0; i < executionStatus.Length; ++i) {
+ executionStatus[i] = TaskStatus.Inactive;
+ }
+ currentChildIndex = 0;
+ }
+ }
+}
\ No newline at end of file diff --git a/Client/Assets/Behavior Designer/Runtime/Composites/Parallel.cs.meta b/Client/Assets/Behavior Designer/Runtime/Composites/Parallel.cs.meta new file mode 100644 index 00000000..83e99844 --- /dev/null +++ b/Client/Assets/Behavior Designer/Runtime/Composites/Parallel.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2
+guid: 4a7063721a0dbc04787bec1b0507f9ae
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
diff --git a/Client/Assets/Behavior Designer/Runtime/Composites/ParallelSelector.cs b/Client/Assets/Behavior Designer/Runtime/Composites/ParallelSelector.cs new file mode 100644 index 00000000..13e6624a --- /dev/null +++ b/Client/Assets/Behavior Designer/Runtime/Composites/ParallelSelector.cs @@ -0,0 +1,87 @@ +namespace BehaviorDesigner.Runtime.Tasks
+{
+ [TaskDescription("Similar to the selector task, the parallel selector task will return success as soon as a child task returns success. " +
+ "The difference is that the parallel task will run all of its children tasks simultaneously versus running each task one at a time. " +
+ "If one tasks returns success the parallel selector task will end all of the child tasks and return success. " +
+ "If every child task returns failure then the parallel selector task will return failure.")]
+ [HelpURL("http://www.opsive.com/assets/BehaviorDesigner/documentation.php?id=28")]
+ [TaskIcon("{SkinColor}ParallelSelectorIcon.png")]
+ public class ParallelSelector : Composite
+ {
+ // The index of the child that is currently running or is about to run.
+ private int currentChildIndex;
+ // The task status of every child task.
+ private TaskStatus[] executionStatus;
+
+ public override void OnAwake()
+ {
+ // Create a new task status array that will hold the execution status of all of the children tasks.
+ executionStatus = new TaskStatus[children.Count];
+ }
+
+ public override void OnChildStarted(int childIndex)
+ {
+ // One of the children has started to run. Increment the child index and set the current task status of that child to running.
+ currentChildIndex++;
+ executionStatus[childIndex] = TaskStatus.Running;
+ }
+
+ public override bool CanRunParallelChildren()
+ {
+ // This task can run parallel children.
+ return true;
+ }
+
+ public override int CurrentChildIndex()
+ {
+ return currentChildIndex;
+ }
+
+ public override bool CanExecute()
+ {
+ // We can continue executing if we have more children that haven't been started yet.
+ return currentChildIndex < children.Count;
+ }
+
+ public override void OnChildExecuted(int childIndex, TaskStatus childStatus)
+ {
+ // One of the children has finished running. Set the task status.
+ executionStatus[childIndex] = childStatus;
+ }
+
+ public override void OnConditionalAbort(int childIndex)
+ {
+ // Start from the beginning on an abort
+ currentChildIndex = 0;
+ for (int i = 0; i < executionStatus.Length; ++i) {
+ executionStatus[i] = TaskStatus.Inactive;
+ }
+ }
+
+ public override TaskStatus OverrideStatus(TaskStatus status)
+ {
+ // 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
+ // or succeeded. If a task is still running then all of the children are not done executing and the parallel selector task should continue to return a task status of running.
+ // If a task succeeded then return success. The Behavior Manager will stop all of the children tasks. If no child task is running or has succeeded then the parallel selector
+ // task failed and it will return failure.
+ bool childrenComplete = true;
+ for (int i = 0; i < executionStatus.Length; ++i) {
+ if (executionStatus[i] == TaskStatus.Running) {
+ childrenComplete = false;
+ } else if (executionStatus[i] == TaskStatus.Success) {
+ return TaskStatus.Success;
+ }
+ }
+ return (childrenComplete ? TaskStatus.Failure : TaskStatus.Running);
+ }
+
+ public override void OnEnd()
+ {
+ // Reset the execution status and the child index back to their starting values.
+ for (int i = 0; i < executionStatus.Length; ++i) {
+ executionStatus[i] = TaskStatus.Inactive;
+ }
+ currentChildIndex = 0;
+ }
+ }
+}
\ No newline at end of file diff --git a/Client/Assets/Behavior Designer/Runtime/Composites/ParallelSelector.cs.meta b/Client/Assets/Behavior Designer/Runtime/Composites/ParallelSelector.cs.meta new file mode 100644 index 00000000..37b9893c --- /dev/null +++ b/Client/Assets/Behavior Designer/Runtime/Composites/ParallelSelector.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2
+guid: 52e4e27ad95cedb41a3bc2c5f5ed0b54
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
diff --git a/Client/Assets/Behavior Designer/Runtime/Composites/PrioritySelector.cs b/Client/Assets/Behavior Designer/Runtime/Composites/PrioritySelector.cs new file mode 100644 index 00000000..5f2dac27 --- /dev/null +++ b/Client/Assets/Behavior Designer/Runtime/Composites/PrioritySelector.cs @@ -0,0 +1,72 @@ +using System.Collections.Generic;
+
+namespace BehaviorDesigner.Runtime.Tasks
+{
+ [TaskDescription("Similar to the selector task, the priority selector task will return success as soon as a child task returns success. " +
+ "Instead of running the tasks sequentially from left to right within the tree, the priority selector will ask the task what its priority is to determine the order. " +
+ "The higher priority tasks have a higher chance at being run first.")]
+ [HelpURL("http://www.opsive.com/assets/BehaviorDesigner/documentation.php?id=29")]
+ [TaskIcon("{SkinColor}PrioritySelectorIcon.png")]
+ public class PrioritySelector : Composite
+ {
+ // The index of the child that is currently running or is about to run.
+ private int currentChildIndex = 0;
+ // The task status of every child task.
+ private TaskStatus executionStatus = TaskStatus.Inactive;
+ // The order to run its children in.
+ private List<int> childrenExecutionOrder = new List<int>();
+
+ public override void OnStart()
+ {
+ // Make sure the list is empty before we add child indexes to it.
+ childrenExecutionOrder.Clear();
+
+ // Loop through each child task and determine its priority. The higher the priority the lower it goes within the list. The task with the highest
+ // priority will be first in the list and will be executed first.
+ for (int i = 0; i < children.Count; ++i) {
+ float priority = children[i].GetPriority();
+ int insertIndex = childrenExecutionOrder.Count;
+ for (int j = 0; j < childrenExecutionOrder.Count; ++j) {
+ if (children[childrenExecutionOrder[j]].GetPriority() < priority) {
+ insertIndex = j;
+ break;
+ }
+ }
+ childrenExecutionOrder.Insert(insertIndex, i);
+ }
+ }
+
+ public override int CurrentChildIndex()
+ {
+ // Use the execution order list in order to determine the current child index.
+ return childrenExecutionOrder[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 success.
+ return currentChildIndex < children.Count && executionStatus != TaskStatus.Success;
+ }
+
+ 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 = 0;
+ }
+ }
+}
\ No newline at end of file diff --git a/Client/Assets/Behavior Designer/Runtime/Composites/PrioritySelector.cs.meta b/Client/Assets/Behavior Designer/Runtime/Composites/PrioritySelector.cs.meta new file mode 100644 index 00000000..fd866f4e --- /dev/null +++ b/Client/Assets/Behavior Designer/Runtime/Composites/PrioritySelector.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2
+guid: 8b5aa86ad86e94f41841abd04bd96f2a
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
diff --git a/Client/Assets/Behavior Designer/Runtime/Composites/RandomSelector.cs b/Client/Assets/Behavior Designer/Runtime/Composites/RandomSelector.cs new file mode 100644 index 00000000..ed625e1f --- /dev/null +++ b/Client/Assets/Behavior Designer/Runtime/Composites/RandomSelector.cs @@ -0,0 +1,102 @@ +using UnityEngine;
+using System.Collections.Generic;
+
+namespace BehaviorDesigner.Runtime.Tasks
+{
+ [TaskDescription("Similar to the selector task, the random selector task will return success as soon as a child task returns success. " +
+ "The difference is that the random selector class will run its children in a random order. The selector task is deterministic " +
+ "in that it will always run the tasks from left to right within the tree. The random selector task shuffles the child tasks up and then begins " +
+ "execution in a random order. Other than that the random selector class is the same as the selector class. It will continue running tasks " +
+ "until a task completes successfully. If no child tasks return success then it will return failure.")]
+ [HelpURL("http://www.opsive.com/assets/BehaviorDesigner/documentation.php?id=30")]
+ [TaskIcon("{SkinColor}RandomSelectorIcon.png")]
+ public class RandomSelector : Composite
+ {
+ [Tooltip("Seed the random number generator to make things easier to debug")]
+ public int seed = 0;
+ [Tooltip("Do we want to use the seed?")]
+ public bool useSeed = false;
+
+ // A list of indexes of every child task. This list is used by the Fischer-Yates shuffle algorithm.
+ private List<int> childIndexList = new List<int>();
+ // The random child index execution order.
+ private Stack<int> childrenExecutionOrder = new Stack<int>();
+ // The task status of the last child ran.
+ private TaskStatus executionStatus = TaskStatus.Inactive;
+
+ public override void OnAwake()
+ {
+ // If specified, use the seed provided.
+ if (useSeed) {
+ Random.InitState(seed);
+ }
+
+ // Add the index of each child to a list to make the Fischer-Yates shuffle possible.
+ childIndexList.Clear();
+ for (int i = 0; i < children.Count; ++i) {
+ childIndexList.Add(i);
+ }
+ }
+
+ public override void OnStart()
+ {
+ // Randomize the indecies
+ ShuffleChilden();
+ }
+
+ public override int CurrentChildIndex()
+ {
+ // Peek will return the index at the top of the stack.
+ return childrenExecutionOrder.Peek();
+ }
+
+ public override bool CanExecute()
+ {
+ // Continue exectuion if no task has return success and indexes still exist on the stack.
+ return childrenExecutionOrder.Count > 0 && executionStatus != TaskStatus.Success;
+ }
+
+ public override void OnChildExecuted(TaskStatus childStatus)
+ {
+ // Pop the top index from the stack and set the execution status.
+ if (childrenExecutionOrder.Count > 0) {
+ childrenExecutionOrder.Pop();
+ }
+ executionStatus = childStatus;
+ }
+
+ public override void OnConditionalAbort(int childIndex)
+ {
+ // Start from the beginning on an abort
+ childrenExecutionOrder.Clear();
+ executionStatus = TaskStatus.Inactive;
+ ShuffleChilden();
+ }
+
+ public override void OnEnd()
+ {
+ // All of the children have run. Reset the variables back to their starting values.
+ executionStatus = TaskStatus.Inactive;
+ childrenExecutionOrder.Clear();
+ }
+
+ public override void OnReset()
+ {
+ // Reset the public properties back to their original values
+ seed = 0;
+ useSeed = false;
+ }
+
+ private void ShuffleChilden()
+ {
+ // Use Fischer-Yates shuffle to randomize the child index order.
+ for (int i = childIndexList.Count; i > 0; --i) {
+ int j = Random.Range(0, i);
+ int index = childIndexList[j];
+ childrenExecutionOrder.Push(index);
+ childIndexList[j] = childIndexList[i - 1];
+ childIndexList[i - 1] = index;
+ }
+ }
+ }
+}
\ No newline at end of file diff --git a/Client/Assets/Behavior Designer/Runtime/Composites/RandomSelector.cs.meta b/Client/Assets/Behavior Designer/Runtime/Composites/RandomSelector.cs.meta new file mode 100644 index 00000000..1f33af10 --- /dev/null +++ b/Client/Assets/Behavior Designer/Runtime/Composites/RandomSelector.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2
+guid: 4952cbfc1e77be24b99e34c9acffc2a0
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
diff --git a/Client/Assets/Behavior Designer/Runtime/Composites/RandomSequence.cs b/Client/Assets/Behavior Designer/Runtime/Composites/RandomSequence.cs new file mode 100644 index 00000000..0d4e2223 --- /dev/null +++ b/Client/Assets/Behavior Designer/Runtime/Composites/RandomSequence.cs @@ -0,0 +1,103 @@ +using UnityEngine;
+using System.Collections.Generic;
+
+namespace BehaviorDesigner.Runtime.Tasks
+{
+ [TaskDescription("Similar to the sequence task, the random sequence task will return success as soon as every child task returns success. " +
+ "The difference is that the random sequence class will run its children in a random order. The sequence task is deterministic " +
+ "in that it will always run the tasks from left to right within the tree. The random sequence task shuffles the child tasks up and then begins " +
+ "execution in a random order. Other than that the random sequence class is the same as the sequence class. It will stop running tasks " +
+ "as soon as a single task ends in failure. On a task failure it will stop executing all of the child tasks and return failure. " +
+ "If no child returns failure then it will return success.")]
+ [HelpURL("http://www.opsive.com/assets/BehaviorDesigner/documentation.php?id=31")]
+ [TaskIcon("{SkinColor}RandomSequenceIcon.png")]
+ public class RandomSequence : Composite
+ {
+ [Tooltip("Seed the random number generator to make things easier to debug")]
+ public int seed = 0;
+ [Tooltip("Do we want to use the seed?")]
+ public bool useSeed = false;
+
+ // A list of indexes of every child task. This list is used by the Fischer-Yates shuffle algorithm.
+ private List<int> childIndexList = new List<int>();
+ // The random child index execution order.
+ private Stack<int> childrenExecutionOrder = new Stack<int>();
+ // The task status of the last child ran.
+ private TaskStatus executionStatus = TaskStatus.Inactive;
+
+ public override void OnAwake()
+ {
+ // If specified, use the seed provided.
+ if (useSeed) {
+ Random.InitState(seed);
+ }
+
+ // Add the index of each child to a list to make the Fischer-Yates shuffle possible.
+ childIndexList.Clear();
+ for (int i = 0; i < children.Count; ++i) {
+ childIndexList.Add(i);
+ }
+ }
+
+ public override void OnStart()
+ {
+ // Randomize the indecies
+ ShuffleChilden();
+ }
+
+ public override int CurrentChildIndex()
+ {
+ // Peek will return the index at the top of the stack.
+ return childrenExecutionOrder.Peek();
+ }
+
+ public override bool CanExecute()
+ {
+ // Continue exectuion if no task has return failure and indexes still exist on the stack.
+ return childrenExecutionOrder.Count > 0 && executionStatus != TaskStatus.Failure;
+ }
+
+ public override void OnChildExecuted(TaskStatus childStatus)
+ {
+ // Pop the top index from the stack and set the execution status.
+ if (childrenExecutionOrder.Count > 0) {
+ childrenExecutionOrder.Pop();
+ }
+ executionStatus = childStatus;
+ }
+
+ public override void OnConditionalAbort(int childIndex)
+ {
+ // Start from the beginning on an abort
+ childrenExecutionOrder.Clear();
+ executionStatus = TaskStatus.Inactive;
+ ShuffleChilden();
+ }
+
+ public override void OnEnd()
+ {
+ // All of the children have run. Reset the variables back to their starting values.
+ executionStatus = TaskStatus.Inactive;
+ childrenExecutionOrder.Clear();
+ }
+
+ public override void OnReset()
+ {
+ // Reset the public properties back to their original values
+ seed = 0;
+ useSeed = false;
+ }
+
+ private void ShuffleChilden()
+ {
+ // Use Fischer-Yates shuffle to randomize the child index order.
+ for (int i = childIndexList.Count; i > 0; --i) {
+ int j = Random.Range(0, i);
+ int index = childIndexList[j];
+ childrenExecutionOrder.Push(index);
+ childIndexList[j] = childIndexList[i - 1];
+ childIndexList[i - 1] = index;
+ }
+ }
+ }
+}
\ No newline at end of file diff --git a/Client/Assets/Behavior Designer/Runtime/Composites/RandomSequence.cs.meta b/Client/Assets/Behavior Designer/Runtime/Composites/RandomSequence.cs.meta new file mode 100644 index 00000000..0f3ca379 --- /dev/null +++ b/Client/Assets/Behavior Designer/Runtime/Composites/RandomSequence.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2
+guid: 11b102c97eb687b4a9ce1473a334c3dd
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
diff --git a/Client/Assets/Behavior Designer/Runtime/Composites/Selector.cs b/Client/Assets/Behavior Designer/Runtime/Composites/Selector.cs new file mode 100644 index 00000000..e85b1ca5 --- /dev/null +++ b/Client/Assets/Behavior Designer/Runtime/Composites/Selector.cs @@ -0,0 +1,46 @@ +namespace BehaviorDesigner.Runtime.Tasks
+{
+ [TaskDescription("The selector task is similar to an \"or\" operation. It will return success as soon as one of its child tasks return success. " +
+ "If a child task returns failure then it will sequentially run the next task. If no child task returns success then it will return failure.")]
+ [HelpURL("http://www.opsive.com/assets/BehaviorDesigner/documentation.php?id=26")]
+ [TaskIcon("{SkinColor}SelectorIcon.png")]
+ public class Selector : Composite
+ {
+ // The index of the child that is currently running or is about to run.
+ private int currentChildIndex = 0;
+ // 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 success.
+ return currentChildIndex < children.Count && executionStatus != TaskStatus.Success;
+ }
+
+ 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 = 0;
+ }
+ }
+}
\ No newline at end of file diff --git a/Client/Assets/Behavior Designer/Runtime/Composites/Selector.cs.meta b/Client/Assets/Behavior Designer/Runtime/Composites/Selector.cs.meta new file mode 100644 index 00000000..3552ecf6 --- /dev/null +++ b/Client/Assets/Behavior Designer/Runtime/Composites/Selector.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2
+guid: 7cb8dcec14880a443841212e6b595d4f
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
diff --git a/Client/Assets/Behavior Designer/Runtime/Composites/SelectorEvaluator.cs b/Client/Assets/Behavior Designer/Runtime/Composites/SelectorEvaluator.cs new file mode 100644 index 00000000..08bd350c --- /dev/null +++ b/Client/Assets/Behavior Designer/Runtime/Composites/SelectorEvaluator.cs @@ -0,0 +1,120 @@ +using UnityEngine;
+
+namespace BehaviorDesigner.Runtime.Tasks
+{
+ [TaskDescription("The selector evaluator is a selector task which reevaluates its children every tick. It will run the lowest priority child which returns a task status of running. " +
+ "This is done each tick. If a higher priority child is running and the next frame a lower priority child wants to run it will interrupt the higher priority child. " +
+ "The selector evaluator will return success as soon as the first child returns success otherwise it will keep trying higher priority children. This task mimics " +
+ "the conditional abort functionality except the child tasks don't always have to be conditional tasks.")]
+ [HelpURL("http://www.opsive.com/assets/BehaviorDesigner/documentation.php?id=109")]
+ [TaskIcon("{SkinColor}SelectorEvaluatorIcon.png")]
+ public class SelectorEvaluator : Composite
+ {
+ // The index of the child that is currently running or is about to run.
+ private int currentChildIndex = 0;
+ // The task status of the last child ran.
+ private TaskStatus executionStatus = TaskStatus.Inactive;
+ // The index of the child that was running before the tree started to be reevaluated.
+ private int storedCurrentChildIndex = -1;
+ // The task status of the last child ran before the tree started to be reevaluated.
+ private TaskStatus storedExecutionStatus = TaskStatus.Inactive;
+
+ public override int CurrentChildIndex()
+ {
+ return currentChildIndex;
+ }
+
+ public override void OnChildStarted(int childIndex)
+ {
+ // The children run sequentially so increment the index and set the status to running.
+ currentChildIndex++;
+ executionStatus = TaskStatus.Running;
+ }
+
+ 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 success.
+ if (executionStatus == TaskStatus.Success || executionStatus == TaskStatus.Running) {
+ return false;
+ }
+
+ // Used the storedCurrentChildIndex if reevaluating, otherwise the currentChildIndex
+ if (storedCurrentChildIndex != -1) {
+ return currentChildIndex < storedCurrentChildIndex - 1;
+ }
+ return currentChildIndex < children.Count;
+ }
+
+ public override void OnChildExecuted(int childIndex, TaskStatus childStatus)
+ {
+ // The child status will be inactive immediately following an abort from OnReevaluationEnded. The status will be running if the
+ // child task is interrupted. Ignore the status for both of these.
+ if (childStatus != TaskStatus.Inactive && childStatus != TaskStatus.Running) {
+ 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 = 0;
+ }
+
+ public override TaskStatus OverrideStatus(TaskStatus status)
+ {
+ return executionStatus;
+ }
+
+ // The selector evaluator task is a parallel task to allow the previous child to continue to run while the higher priority task is active. If the
+ // lower priority child can run then OnReevaluationEnded will interrupt the higher priority task.
+ public override bool CanRunParallelChildren()
+ {
+ return true;
+ }
+
+ // Can reevaluate to allow the lower priority children the chance to rerun.
+ public override bool CanReevaluate()
+ {
+ return true;
+ }
+
+ // The behavior tree wants to start reevaluating the tree.
+ public override bool OnReevaluationStarted()
+ {
+ // Cannot reevaluate if the task hasn't even started yet
+ if (executionStatus == TaskStatus.Inactive) {
+ return false;
+ }
+
+ // Store the current index and execution status because it may need to be resumed.
+ storedCurrentChildIndex = currentChildIndex;
+ storedExecutionStatus = executionStatus;
+ currentChildIndex = 0;
+ executionStatus = TaskStatus.Inactive;
+ return true;
+ }
+
+ // Reevaluation has ended. Determine if a task should be interrupted or resumed from the last index.
+ public override void OnReevaluationEnded(TaskStatus status)
+ {
+ // Interrupt the currently running index if a lower priority child returns a status of running or success.
+ if (executionStatus != TaskStatus.Failure && executionStatus != TaskStatus.Inactive) {
+ BehaviorManager.instance.Interrupt(Owner, children[storedCurrentChildIndex - 1], this);
+ } else {
+ // The lower priority children returned the same status so resume with the current child
+ currentChildIndex = storedCurrentChildIndex;
+ executionStatus = storedExecutionStatus;
+ }
+ storedCurrentChildIndex = -1;
+ storedExecutionStatus = TaskStatus.Inactive;
+ }
+ }
+}
\ No newline at end of file diff --git a/Client/Assets/Behavior Designer/Runtime/Composites/SelectorEvaluator.cs.meta b/Client/Assets/Behavior Designer/Runtime/Composites/SelectorEvaluator.cs.meta new file mode 100644 index 00000000..b55971ba --- /dev/null +++ b/Client/Assets/Behavior Designer/Runtime/Composites/SelectorEvaluator.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2
+guid: 15b5d0aafd7d4f04f8332d33705ebd63
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
diff --git a/Client/Assets/Behavior Designer/Runtime/Composites/Sequence.cs b/Client/Assets/Behavior Designer/Runtime/Composites/Sequence.cs new file mode 100644 index 00000000..c82ce730 --- /dev/null +++ b/Client/Assets/Behavior Designer/Runtime/Composites/Sequence.cs @@ -0,0 +1,46 @@ +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 = 0;
+ // 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 = 0;
+ }
+ }
+}
\ No newline at end of file diff --git a/Client/Assets/Behavior Designer/Runtime/Composites/Sequence.cs.meta b/Client/Assets/Behavior Designer/Runtime/Composites/Sequence.cs.meta new file mode 100644 index 00000000..068578b3 --- /dev/null +++ b/Client/Assets/Behavior Designer/Runtime/Composites/Sequence.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2
+guid: b7226608b64066c40a656d7260249fce
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
|