OpenXR开发实战项目之VR BehaviorDesinger

2023-12-10  本文已影响0人  TonyWan_AR

一、框架视图

二、关键代码

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;
        }
    }
}

三、效果展示



上一篇下一篇

猜你喜欢

热点阅读