summaryrefslogtreecommitdiff
path: root/Client/Assets/Behavior Designer/Runtime/Composites/UtilitySelector.cs
diff options
context:
space:
mode:
authorchai <chaifix@163.com>2021-01-27 16:30:19 +0800
committerchai <chaifix@163.com>2021-01-27 16:30:19 +0800
commit6ee18886c8af3858de5e97599b23086823d9f320 (patch)
treeaed86a8c4887586d976410ecd3d14789b2ee3583 /Client/Assets/Behavior Designer/Runtime/Composites/UtilitySelector.cs
parent97da432c35b8c7aaf9dd2c39e2aa4b1f55f36065 (diff)
*更新Behaviour Designer版本,在最下版本有BUG
Diffstat (limited to 'Client/Assets/Behavior Designer/Runtime/Composites/UtilitySelector.cs')
-rw-r--r--Client/Assets/Behavior Designer/Runtime/Composites/UtilitySelector.cs150
1 files changed, 150 insertions, 0 deletions
diff --git a/Client/Assets/Behavior Designer/Runtime/Composites/UtilitySelector.cs b/Client/Assets/Behavior Designer/Runtime/Composites/UtilitySelector.cs
new file mode 100644
index 00000000..23fd6a54
--- /dev/null
+++ b/Client/Assets/Behavior Designer/Runtime/Composites/UtilitySelector.cs
@@ -0,0 +1,150 @@
+using System.Collections.Generic;
+
+namespace BehaviorDesigner.Runtime.Tasks
+{
+ [TaskDescription("The utility selector task evaluates the child tasks using Utility Theory AI. The child task can override the GetUtility method and return the utility value " +
+ "at that particular time. The task with the highest utility value will be selected and the existing running task will be aborted. The utility selector " +
+ "task reevaluates its children every tick.")]
+ [HelpURL("http://www.opsive.com/assets/BehaviorDesigner/documentation.php?id=134")]
+ [TaskIcon("{SkinColor}UtilitySelectorIcon.png")]
+ public class UtilitySelector : Composite
+ {
+ // The index of the child that is currently running or is about to run.
+ private int currentChildIndex = 0;
+ // The highest utility value
+ private float highestUtility;
+ // The task status of the last child ran.
+ private TaskStatus executionStatus = TaskStatus.Inactive;
+ // Is the task being reevaluated?
+ private bool reevaluating;
+ // A list of children that can execute.
+ private List<int> availableChildren = new List<int>();
+
+ public override void OnStart()
+ {
+ highestUtility = float.MinValue;
+
+ // Loop through each child task and determine its utility. The task with the highest utility will run first.
+ availableChildren.Clear();
+ for (int i = 0; i < children.Count; ++i) {
+ float utility = children[i].GetUtility();
+ if (utility > highestUtility) {
+ highestUtility = utility;
+ currentChildIndex = i;
+ }
+ availableChildren.Add(i);
+ }
+ }
+
+ public override int CurrentChildIndex()
+ {
+ // The currentChildIndex is the task with the highest utility.
+ return currentChildIndex;
+ }
+
+ public override void OnChildStarted(int childIndex)
+ {
+ // The child has started - set the execution status.
+ executionStatus = TaskStatus.Running;
+ }
+
+ public override bool CanExecute()
+ {
+ // Continue to execute new tasks until a task returns success or there are no more children left. If reevaluating then return false
+ // immediately because each task doesn't need to be reevaluted.
+ if (executionStatus == TaskStatus.Success || executionStatus == TaskStatus.Running || reevaluating) {
+ return false;
+ }
+ return availableChildren.Count > 0;
+ }
+
+ 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;
+ // If the execution status is failure then a new task needs to be selected. Remove the current task from the available children
+ // and select the next highest utility child.
+ if (executionStatus == TaskStatus.Failure) {
+ availableChildren.Remove(childIndex);
+
+ highestUtility = float.MinValue;
+ for (int i = 0; i < availableChildren.Count; ++i) {
+ float utility = children[availableChildren[i]].GetUtility();
+ if (utility > highestUtility) {
+ highestUtility = utility;
+ currentChildIndex = availableChildren[i];
+ }
+ }
+ }
+ }
+ }
+
+ 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 utility selector task is a parallel task to allow the task utility to be reevaluated. The higest utility task will always run.
+ public override bool CanRunParallelChildren()
+ {
+ return true;
+ }
+
+ // Can reevaluate to allow the task utilities to be 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;
+ }
+
+ reevaluating = true;
+ return true;
+ }
+
+ // Determine if a task with a higher utility exists.
+ public override void OnReevaluationEnded(TaskStatus status)
+ {
+ reevaluating = false;
+
+ // Loop through all of the available children and pick the task with the highest utility.
+ int prevChildIndex = currentChildIndex;
+ highestUtility = float.MinValue;
+ for (int i = 0; i < availableChildren.Count; ++i) {
+ float utility = children[availableChildren[i]].GetUtility();
+ if (utility > highestUtility) {
+ highestUtility = utility;
+ currentChildIndex = availableChildren[i];
+ }
+ }
+
+ // If the index is different then the current child task should be aborted and the higher utility task should be run.
+ if (prevChildIndex != currentChildIndex) {
+ BehaviorManager.instance.Interrupt(Owner, children[prevChildIndex], this);
+ executionStatus = TaskStatus.Inactive;
+ }
+ }
+ }
+} \ No newline at end of file