一、框架视图
二、关键代码
myCanSeeObject
using BehaviorDesigner.Runtime.Tasks;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using BehaviorDesigner.Runtime;
//这个脚本是用来判断目标是否在视野内
public class myCanSeeObject : Conditional
{
public Transform[] targets;
public float filedOfViewAngle = 90;
public float viewDistance = 7;
public SharedTransform target;
public override TaskStatus OnUpdate()
{
if (targets == null)
{
return TaskStatus.Failure;
}
foreach (var target in targets)
{
float distance = (target.position - transform.position).magnitude;
float angle = Vector3.Angle(transform.forward, target.position - transform.position);
if (distance < viewDistance && angle < filedOfViewAngle)
{
this.target.Value = target;
return TaskStatus.Success;
}
}
return TaskStatus.Failure;
}
}
mySeek
using BehaviorDesigner.Runtime.Tasks;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using BehaviorDesigner.Runtime;
//这个脚本的作用就是控制游戏物体到达目标位置
public class mySeek : Action //这个任务的调用都是由Behavior Desinger行为树去控制的
{
public float speed;
public SharedTransform target; //要到达的目标位置
public float arriveDistance = 0.1f;
private float sqrArriveDistance;
public override void OnStart()
{
sqrArriveDistance = arriveDistance * arriveDistance;
}
//当进入到这个任务的时候,就会调用这个方法,一直到任务结束,会进行一些位置的计算
//这个方法的调用频率,默认是和unity里面的帧率保持一致
public override TaskStatus OnUpdate()
{
//安全校验
if(target == null || target.Value == null)
{
return TaskStatus.Failure;
}
transform.LookAt(target.Value.position);//直接朝向目标位置
transform.position = Vector3.MoveTowards(transform.position, target.Value.position, speed*Time.deltaTime);
if((target.Value.position - transform.position).sqrMagnitude<arriveDistance * sqrArriveDistance)
{
return TaskStatus.Success; //如果距离目标位置的距离比较小,认为到达了目标
}
return TaskStatus.Running;
}
}
PerformInterruption
namespace BehaviorDesigner.Runtime.Tasks
{
[TaskDescription("Perform the actual interruption. This will immediately stop the specified tasks from running and will return success or failure depending on the value of interrupt success.")]
[TaskIcon("{SkinColor}PerformInterruptionIcon.png")]
public class PerformInterruption : Action
{
[Tooltip("The list of tasks to interrupt. Can be any number of tasks")]
public Interrupt[] interruptTasks;
[Tooltip("When we interrupt the task should we return a task status of success?")]
public SharedBool interruptSuccess;
public override TaskStatus OnUpdate()
{
// Loop through all of the tasks and fire an interruption. Once complete return success.
for (int i = 0; i < interruptTasks.Length; ++i) {
interruptTasks[i].DoInterrupt(interruptSuccess.Value ? TaskStatus.Success : TaskStatus.Failure);
}
return TaskStatus.Success;
}
public override void OnReset()
{
// Reset the properties back to their original values.
interruptTasks = null;
interruptSuccess = false;
}
}
}
RestartBehaviorTree
using UnityEngine;
namespace BehaviorDesigner.Runtime.Tasks
{
[TaskDescription("Restarts a behavior tree, returns success after it has been restarted.")]
[TaskIcon("{SkinColor}RestartBehaviorTreeIcon.png")]
public class RestartBehaviorTree : Action
{
[Tooltip("The GameObject of the behavior tree that should be restarted. If null use the current behavior")]
public SharedGameObject behaviorGameObject;
[Tooltip("The group of the behavior tree that should be restarted")]
public SharedInt group;
private Behavior behavior;
public override void OnAwake()
{
var behaviorTrees = GetDefaultGameObject(behaviorGameObject.Value).GetComponents<Behavior>();
if (behaviorTrees.Length == 1) {
behavior = behaviorTrees[0];
} else if (behaviorTrees.Length > 1) {
for (int i = 0; i < behaviorTrees.Length; ++i) {
if (behaviorTrees[i].Group == group.Value) {
behavior = behaviorTrees[i];
break;
}
}
// If the group can't be found then use the first behavior tree
if (behavior == null) {
behavior = behaviorTrees[0];
}
}
}
public override TaskStatus OnUpdate()
{
if (behavior == null) {
return TaskStatus.Failure;
}
// Stop the behavior tree
behavior.DisableBehavior();
// Start the behavior tree back up
behavior.EnableBehavior();
// Return success
return TaskStatus.Success;
}
public override void OnReset()
{
// Reset the properties back to their original values.
behavior = null;
}
}
}
StackedAction
using UnityEngine;
namespace BehaviorDesigner.Runtime.Tasks
{
[TaskDescription("Allows multiple action tasks to be added to a single node.")]
[TaskIcon("{SkinColor}StackedActionIcon.png")]
public class StackedAction : Action
{
[InspectTask]
public Action[] actions;
public enum ComparisonType
{
Sequence,
Selector
}
[Tooltip("Specifies if the tasks should be traversed with an AND (Sequence) or an OR (Selector).")]
public ComparisonType comparisonType;
[Tooltip("Should the tasks be labeled within the graph?")]
public bool graphLabel;
public override void OnAwake()
{
if (actions == null) {
return;
}
for (int i = 0; i < actions.Length; ++i) {
if (actions[i] == null) {
continue;
}
actions[i].GameObject = gameObject;
actions[i].Transform = transform;
actions[i].Owner = Owner;
#if UNITY_EDITOR || DLL_RELEASE || DLL_DEBUG
actions[i].NodeData = new NodeData();
#endif
actions[i].OnAwake();
}
}
public override void OnStart()
{
if (actions == null) {
return;
}
for (int i = 0; i < actions.Length; ++i) {
if (actions[i] == null) {
continue;
}
actions[i].OnStart();
}
}
public override TaskStatus OnUpdate()
{
if (actions == null) {
return TaskStatus.Failure;
}
for (int i = 0; i < actions.Length; ++i) {
if (actions[i] == null) {
continue;
}
var executionStatus = actions[i].OnUpdate();
#if UNITY_EDITOR || DLL_RELEASE || DLL_DEBUG
actions[i].NodeData.ExecutionStatus = executionStatus;
if (actions[i].NodeData.ExecutionStatus == TaskStatus.Running) {
Debug.LogWarning("Warning: The action task returned a status of running when action tasks should only return success or failure.");
}
#endif
if (comparisonType == ComparisonType.Sequence && executionStatus == TaskStatus.Failure) {
return TaskStatus.Failure;
} else if (comparisonType == ComparisonType.Selector && executionStatus == TaskStatus.Success) {
return TaskStatus.Success;
}
}
return comparisonType == ComparisonType.Sequence ? TaskStatus.Success : TaskStatus.Failure;
}
public override void OnFixedUpdate()
{
if (actions == null) {
return;
}
for (int i = 0; i < actions.Length; ++i) {
if (actions[i] == null) {
continue;
}
actions[i].OnFixedUpdate();
}
}
public override void OnLateUpdate()
{
if (actions == null) {
return;
}
for (int i = 0; i < actions.Length; ++i) {
if (actions[i] == null) {
continue;
}
actions[i].OnLateUpdate();
}
}
public override void OnEnd()
{
if (actions == null) {
return;
}
for (int i = 0; i < actions.Length; ++i) {
if (actions[i] == null) {
continue;
}
actions[i].OnEnd();
}
}
public override void OnTriggerEnter(Collider other)
{
if (actions == null) {
return;
}
for (int i = 0; i < actions.Length; ++i) {
if (actions[i] == null) {
continue;
}
actions[i].OnTriggerEnter(other);
}
}
public override void OnTriggerEnter2D(Collider2D other)
{
if (actions == null) {
return;
}
for (int i = 0; i < actions.Length; ++i) {
if (actions[i] == null) {
continue;
}
actions[i].OnTriggerEnter2D(other);
}
}
public override void OnTriggerExit(Collider other)
{
if (actions == null) {
return;
}
for (int i = 0; i < actions.Length; ++i) {
if (actions[i] == null) {
continue;
}
actions[i].OnTriggerExit(other);
}
}
public override void OnTriggerExit2D(Collider2D other)
{
if (actions == null) {
return;
}
for (int i = 0; i < actions.Length; ++i) {
if (actions[i] == null) {
continue;
}
actions[i].OnTriggerExit2D(other);
}
}
public override void OnCollisionEnter(Collision collision)
{
if (actions == null) {
return;
}
for (int i = 0; i < actions.Length; ++i) {
if (actions[i] == null) {
continue;
}
actions[i].OnCollisionEnter(collision);
}
}
public override void OnCollisionEnter2D(Collision2D collision)
{
if (actions == null) {
return;
}
for (int i = 0; i < actions.Length; ++i) {
if (actions[i] == null) {
continue;
}
actions[i].OnCollisionEnter2D(collision);
}
}
public override void OnCollisionExit(Collision collision)
{
if (actions == null) {
return;
}
for (int i = 0; i < actions.Length; ++i) {
if (actions[i] == null) {
continue;
}
actions[i].OnCollisionExit(collision);
}
}
public override void OnCollisionExit2D(Collision2D collision)
{
if (actions == null) {
return;
}
for (int i = 0; i < actions.Length; ++i) {
if (actions[i] == null) {
continue;
}
actions[i].OnCollisionExit2D(collision);
}
}
public override string OnDrawNodeText()
{
if (actions == null || !graphLabel) {
return string.Empty;
}
var text = string.Empty;
for (int i = 0; i < actions.Length; ++i) {
if (actions[i] == null) {
continue;
}
if (!string.IsNullOrEmpty(text)) {
text += "\n";
}
text += actions[i].GetType().Name;
}
return text;
}
public override void OnReset()
{
if (actions == null) {
return;
}
for (int i = 0; i < actions.Length; ++i) {
if (actions[i] == null) {
continue;
}
actions[i].OnReset();
}
}
}
}
ParallelComplete
namespace BehaviorDesigner.Runtime.Tasks
{
[TaskDescription("Similar to the parallel selector task, except the parallel complete task will return the child status as soon as the child returns success or failure." +
"The child tasks are executed simultaneously.")]
[TaskIcon("{SkinColor}ParallelCompleteIcon.png")]
public class ParallelComplete : 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)
{
if (currentChildIndex == 0) {
return TaskStatus.Success;
}
// Return the child task's status as soon as a child task returns success or failure.
for (int i = 0; i < currentChildIndex; ++i) {
if (executionStatus[i] == TaskStatus.Success || executionStatus[i] == TaskStatus.Failure) {
return executionStatus[i];
}
}
return 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;
}
}
}
RandomSelector
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.")]
[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;
}
}
}
}
Sequence
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.")]
[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;
}
}
}
StackedConditional
using UnityEngine;
namespace BehaviorDesigner.Runtime.Tasks
{
[TaskDescription("Allows multiple conditional tasks to be added to a single node.")]
[TaskIcon("{SkinColor}StackedConditionalIcon.png")]
public class StackedConditional : Conditional
{
[InspectTask]
public Conditional[] conditionals;
public enum ComparisonType
{
Sequence,
Selector
}
[Tooltip("Specifies if the tasks should be traversed with an AND (Sequence) or an OR (Selector).")]
public ComparisonType comparisonType;
[Tooltip("Should the tasks be labeled within the graph?")]
public bool graphLabel;
public override void OnAwake()
{
if (conditionals == null) {
return;
}
for (int i = 0; i < conditionals.Length; ++i) {
if (conditionals[i] == null) {
continue;
}
conditionals[i].GameObject = gameObject;
conditionals[i].Transform = transform;
conditionals[i].Owner = Owner;
#if UNITY_EDITOR || DLL_RELEASE || DLL_DEBUG
conditionals[i].NodeData = new NodeData();
#endif
conditionals[i].OnAwake();
}
}
public override void OnStart()
{
if (conditionals == null) {
return;
}
for (int i = 0; i < conditionals.Length; ++i) {
if (conditionals[i] == null) {
continue;
}
conditionals[i].OnStart();
}
}
public override TaskStatus OnUpdate()
{
if (conditionals == null) {
return TaskStatus.Failure;
}
for (int i = 0; i < conditionals.Length; ++i) {
if (conditionals[i] == null) {
continue;
}
var executionStatus = conditionals[i].OnUpdate();
#if UNITY_EDITOR || DLL_RELEASE || DLL_DEBUG
conditionals[i].NodeData.ExecutionStatus = executionStatus;
if (conditionals[i].NodeData.ExecutionStatus == TaskStatus.Running) {
Debug.LogWarning("Warning: The conditional task returned a status of running when conditional tasks should only return success or failure.");
}
#endif
if (comparisonType == ComparisonType.Sequence && executionStatus == TaskStatus.Failure) {
return TaskStatus.Failure;
} else if (comparisonType == ComparisonType.Selector && executionStatus == TaskStatus.Success) {
return TaskStatus.Success;
}
}
return comparisonType == ComparisonType.Sequence ? TaskStatus.Success : TaskStatus.Failure;
}
public override void OnFixedUpdate()
{
if (conditionals == null) {
return;
}
for (int i = 0; i < conditionals.Length; ++i) {
if (conditionals[i] == null) {
continue;
}
conditionals[i].OnFixedUpdate();
}
}
public override void OnLateUpdate()
{
if (conditionals == null) {
return;
}
for (int i = 0; i < conditionals.Length; ++i) {
if (conditionals[i] == null) {
continue;
}
conditionals[i].OnLateUpdate();
}
}
public override void OnEnd()
{
if (conditionals == null) {
return;
}
for (int i = 0; i < conditionals.Length; ++i) {
if (conditionals[i] == null) {
continue;
}
conditionals[i].OnEnd();
}
}
public override void OnTriggerEnter(Collider other)
{
if (conditionals == null) {
return;
}
for (int i = 0; i < conditionals.Length; ++i) {
if (conditionals[i] == null) {
continue;
}
conditionals[i].OnTriggerEnter(other);
}
}
public override void OnTriggerEnter2D(Collider2D other)
{
if (conditionals == null) {
return;
}
for (int i = 0; i < conditionals.Length; ++i) {
if (conditionals[i] == null) {
continue;
}
conditionals[i].OnTriggerEnter2D(other);
}
}
public override void OnTriggerExit(Collider other)
{
if (conditionals == null) {
return;
}
for (int i = 0; i < conditionals.Length; ++i) {
if (conditionals[i] == null) {
continue;
}
conditionals[i].OnTriggerExit(other);
}
}
public override void OnTriggerExit2D(Collider2D other)
{
if (conditionals == null) {
return;
}
for (int i = 0; i < conditionals.Length; ++i) {
if (conditionals[i] == null) {
continue;
}
conditionals[i].OnTriggerExit2D(other);
}
}
public override void OnCollisionEnter(Collision collision)
{
if (conditionals == null) {
return;
}
for (int i = 0; i < conditionals.Length; ++i) {
if (conditionals[i] == null) {
continue;
}
conditionals[i].OnCollisionEnter(collision);
}
}
public override void OnCollisionEnter2D(Collision2D collision)
{
if (conditionals == null) {
return;
}
for (int i = 0; i < conditionals.Length; ++i) {
if (conditionals[i] == null) {
continue;
}
conditionals[i].OnCollisionEnter2D(collision);
}
}
public override void OnCollisionExit(Collision collision)
{
if (conditionals == null) {
return;
}
for (int i = 0; i < conditionals.Length; ++i) {
if (conditionals[i] == null) {
continue;
}
conditionals[i].OnCollisionExit(collision);
}
}
public override void OnCollisionExit2D(Collision2D collision)
{
if (conditionals == null) {
return;
}
for (int i = 0; i < conditionals.Length; ++i) {
if (conditionals[i] == null) {
continue;
}
conditionals[i].OnCollisionExit2D(collision);
}
}
public override string OnDrawNodeText()
{
if (conditionals == null || !graphLabel) {
return string.Empty;
}
var text = string.Empty;
for (int i = 0; i < conditionals.Length; ++i) {
if (conditionals[i] == null) {
continue;
}
if (!string.IsNullOrEmpty(text)) {
text += "\n";
}
text += conditionals[i].GetType().Name;
}
return text;
}
public override void OnReset()
{
if (conditionals == null) {
return;
}
for (int i = 0; i < conditionals.Length; ++i) {
if (conditionals[i] == null) {
continue;
}
conditionals[i].OnReset();
}
}
}
}
ConditionalEvaluator
namespace BehaviorDesigner.Runtime.Tasks
{
[TaskDescription("Evaluates the specified conditional task. If the conditional task returns success then the child task is run and the child status is returned. If the conditional task does not " +
"return success then the child task is not run and a failure status is immediately returned.")]
[TaskIcon("{SkinColor}ConditionalEvaluatorIcon.png")]
public class ConditionalEvaluator : Decorator
{
[Tooltip("Should the conditional task be reevaluated every tick?")]
public SharedBool reevaluate;
[InspectTask]
[Tooltip("The conditional task to evaluate")]
public Conditional conditionalTask;
[Tooltip("Should the inspected conditional task be labeled within the graph?")]
public bool graphLabel;
// The status of the child after it has finished running.
private TaskStatus executionStatus = TaskStatus.Inactive;
private bool checkConditionalTask = true;
private bool conditionalTaskFailed = false;
public override void OnAwake()
{
if (conditionalTask != null) {
conditionalTask.Owner = Owner;
conditionalTask.GameObject = gameObject;
conditionalTask.Transform = transform;
conditionalTask.OnAwake();
}
}
public override void OnStart()
{
if (conditionalTask != null) {
conditionalTask.OnStart();
}
}
public override bool CanExecute()
{
// CanExecute is called when checking the condition within a while loop so it will be called at least twice. Ensure the conditional task is checked only once
if (checkConditionalTask) {
checkConditionalTask = false;
OnUpdate();
}
if (conditionalTaskFailed) {
return false;
}
return executionStatus == TaskStatus.Inactive || executionStatus == TaskStatus.Running;
}
public override bool CanReevaluate()
{
return reevaluate.Value;
}
public override TaskStatus OnUpdate()
{
var childStatus = conditionalTask.OnUpdate();
conditionalTaskFailed = conditionalTask == null || childStatus == TaskStatus.Failure;
return childStatus;
}
public override void OnChildExecuted(TaskStatus childStatus)
{
// Update the execution status after a child has finished running.
executionStatus = childStatus;
}
public override TaskStatus OverrideStatus()
{
// This version of OverrideStatus is called when the conditional evaluator fails reevaluation and has to stop all of its children.
// Therefore, the return status will always be failure
return TaskStatus.Failure;
}
public override TaskStatus OverrideStatus(TaskStatus status)
{
if (conditionalTaskFailed)
return TaskStatus.Failure;
return status;
}
public override void OnEnd()
{
// Reset the variables back to their starting values.
executionStatus = TaskStatus.Inactive;
checkConditionalTask = true;
conditionalTaskFailed = false;
if (conditionalTask != null) {
conditionalTask.OnEnd();
}
}
public override string OnDrawNodeText()
{
if (conditionalTask == null || !graphLabel) {
return string.Empty;
}
return conditionalTask.GetType().Name;
}
public override void OnReset()
{
// Reset the public properties back to their original values.
conditionalTask = null;
}
}
}
ReturnSuccess
namespace BehaviorDesigner.Runtime.Tasks
{
[TaskDescription("The return success task will always return success except when the child task is running.")]
[TaskIcon("{SkinColor}ReturnSuccessIcon.png")]
public class ReturnSuccess : Decorator
{
// The status of the child after it has finished running.
private TaskStatus executionStatus = TaskStatus.Inactive;
public override bool CanExecute()
{
// Continue executing until the child task returns success or failure.
return executionStatus == TaskStatus.Inactive || executionStatus == TaskStatus.Running;
}
public override void OnChildExecuted(TaskStatus childStatus)
{
// Update the execution status after a child has finished running.
executionStatus = childStatus;
}
public override TaskStatus Decorate(TaskStatus status)
{
// Return success even if the child task returned failure.
if (status == TaskStatus.Failure) {
return TaskStatus.Success;
}
return status;
}
public override void OnEnd()
{
// Reset the execution status back to its starting values.
executionStatus = TaskStatus.Inactive;
}
}
}
UntilSuccess
namespace BehaviorDesigner.Runtime.Tasks
{
[TaskDescription("The until success task will keep executing its child task until the child task returns success.")]
[TaskIcon("{SkinColor}UntilSuccessIcon.png")]
public class UntilSuccess : Decorator
{
// The status of the child after it has finished running.
private TaskStatus executionStatus = TaskStatus.Inactive;
public override bool CanExecute()
{
// Keep running until the child task returns success.
return executionStatus == TaskStatus.Failure || executionStatus == TaskStatus.Inactive;
}
public override void OnChildExecuted(TaskStatus childStatus)
{
// Update the execution status after a child has finished running.
executionStatus = childStatus;
}
public override void OnEnd()
{
// Reset the execution status back to its starting values.
executionStatus = TaskStatus.Inactive;
}
}
}
GetAcceleration
using UnityEngine;
using UnityEngine.AI;
namespace BehaviorDesigner.Runtime.Tasks.Unity.UnityNavMeshAgent
{
[TaskCategory("Unity/NavMeshAgent")]
[TaskDescription("Gets the maximum acceleration of an agent as it follows a path, given in units / sec^2.. Returns Success.")]
public class GetAcceleration : Action
{
[Tooltip("The GameObject that the task operates on. If null the task GameObject is used.")]
public SharedGameObject targetGameObject;
[SharedRequired]
[Tooltip("The NavMeshAgent acceleration")]
public SharedFloat storeValue;
// cache the navmeshagent component
private NavMeshAgent navMeshAgent;
private GameObject prevGameObject;
public override void OnStart()
{
var currentGameObject = GetDefaultGameObject(targetGameObject.Value);
if (currentGameObject != prevGameObject) {
navMeshAgent = currentGameObject.GetComponent<NavMeshAgent>();
prevGameObject = currentGameObject;
}
}
public override TaskStatus OnUpdate()
{
if (navMeshAgent == null) {
Debug.LogWarning("NavMeshAgent is null");
return TaskStatus.Failure;
}
storeValue.Value = navMeshAgent.acceleration;
return TaskStatus.Success;
}
public override void OnReset()
{
targetGameObject = null;
storeValue = 0;
}
}
}