以下是纯代码参考, 没有Unity插件的节点编辑导出配置等内容。 行为树的概念, 各种 Unity 插件在这里都没有进行介绍。 代码是根据Unity的 2D Game Kit ,总结提炼的, 对于学习和理解行为树会很有帮助!

using BTAI;using UnityEngine;public class TestBT : MonoBehaviour, BTAI.IBTDebugable{    Root aiRoot = BT.Root();    private void OnEnable()    {        aiRoot.OpenBranch(                BT.If(TestVisibleTarget).OpenBranch(                BT.Call(Aim),                BT.Call(Shoot)                 ),                BT.Sequence().OpenBranch(                BT.Call(Walk),                BT.Wait(5.0f),                BT.Call(Turn),                BT.Wait(1.0f),                BT.Call(Turn)             )        );    }    private void Turn()    {        Debug.Log("执行了 Turn");    }    private void Walk()    {        Debug.Log("执行了 Walk");    }    private void Shoot()    {        Debug.Log("执行了 Shoot");    }    private void Aim()    {        Debug.Log("执行了 Aim");    }    private bool TestVisibleTarget()    {        var isSuccess = UnityEngine.Random.Range(0, 2) == 1;        Debug.Log("执行了 TestVisibleTarget    Result:" + isSuccess);        return isSuccess;    }    private void Update()    {        aiRoot.Tick();    }    public Root GetAIRoot()    {        return aiRoot;    }}

20180725204815235.png

using System.Collections.Generic;using UnityEngine;/// <summary>/// 这只是脚本系统/// 行为树会从Root节点开始遍历子节点。Update中执行/// 每个节点都有相关的操作,但是基本上就是返回三种状态/// ● Success: 节点成功完成任务/// ● Failure: 节点未通过任务/// ● Continue:节点尚未完成任务。/// 但是每个节点的父节点对子节点的结果处理方式还不同。  例如/// ● Test 节点: 测试节点将调用其子节点并在测试为真时返回子节点状态,如果测试为假,则返回Failure而不调用其子节点。/// 行为树的一种构造方式如下:/// Root aiRoot = BT.Root(); /// aiRoot.Do(  /// BT.If(TestVisibleTarget).Do(///  BT.Call(Aim),///  BT.Call(Shoot)///  ),///  BT.Sequence().Do(///  BT.Call(Walk),///  BT.Wait(5.0f),///  BT.Call(Turn),///  BT.Wait(1.0f),///  BT.Call(Turn)///  )/// ); ///然后在Update中 调用   aiRoot.Tick() 。  刚刚构造的行为树是怎么样的检查过程呢?  ///1、首先检查TestVisibleTarget是否返回Ture,如果是继续执行子节点执行Aim函数和Shoot函数///2、TestVisibleTarget是否返回false,if节点将返回Failure, 然后Root 将转向下一个子节点。这是个Sequence节点,它从执行第一个子节点开始。///   1)将调用Walk函数,直接返回 Success,以便Sequence将下一个子节点激活并执行它。///   2)执行Wait 节点,只是要等待5秒,还是第一次调用,所以肯定返回Running状态, 当Sequence从子节点上得到Running状态时,不会更改激活的子节点索引,下次Update的时候还是从这个节点开始执行///3、Update的执行,当Wait节点等待的时间到了的时候,将会返回Success, 以便序列将转到下一个孩子。///脚本中的Node列表 /// Sequence://一个接一个地执行子节点。如果子节点返回://●Success:Sequence将选择下一帧的下一个孩子开始。//●Failure:Sequence将返回到下一帧的第一个子节点(从头开始)。//●Continue:Sequence将在下一帧再次调用该节点。//RandomSequence:// 每次调用时,从子列表中执行一个随机子节点。您可以在构造函数中指定要应用于每个子项的权重列表作为int数组,以使某些子项更有可能被选中。//Selector ://按顺序执行所有子项,直到一个返回Success,然后退出而不执行其余子节点。如果没有返回Success,则此节点将返回Failure。// Condition :// 如果给定函数返回true,则此节点返回Success;如果为false,则返回Failure。// 与其他依赖于子节点结果的节点链接时很有用(例如,Sequence,Selector等)// If ://调用给定的函数。// ●如果返回true,则调用当前活动的子级并返回其状态。// ●否则,它将在不调用其子项的情况下返回Failure// While://只要给定函数返回true,就返回Continue(因此,下一帧将再次从该节点开始,而不会评估所有先前的节点)。//子节点们将陆续被执行。//当函数返回false并且循环中断时,将返回Failure。// Call //调用给定的函数,它将始终返回Success。是动作节点!//Repeat //将连续执行给定次数的所有子节点。//始终返回Continue,直到达到计数,并返回Success。//Wait//将返回Continue,直到达到给定时间(首次调用时开始),然后返回Success。//Trigger //允许在给定的动画师animator中设置Trigger参数(如果最后一个参数设置为false,则取消设置触发器)。始终返回成功。//SetBool//允许在给定的animator中设置布尔参数的值。始终返回成功//SetActive //设置给定GameObject的活动/非活动状态。始终返回成功。/// </summary>namespace BTAI{    public enum BTState    {        Failure,        Success,        Continue,        Abort    }    /// <summary>    /// 节点 对象工厂    /// </summary>    public static class BT    {        public static Root Root() { return new Root(); }        public static Sequence Sequence() { return new Sequence(); }        public static Selector Selector(bool shuffle = false) { return new Selector(shuffle); }        public static Action RunCoroutine(System.Func<IEnumerator<BTState>> coroutine) { return new Action(coroutine); }        public static Action Call(System.Action fn) { return new Action(fn); }        public static ConditionalBranch If(System.Func<bool> fn) { return new ConditionalBranch(fn); }        public static While While(System.Func<bool> fn) { return new While(fn); }        public static Condition Condition(System.Func<bool> fn) { return new Condition(fn); }        public static Repeat Repeat(int count) { return new Repeat(count); }        public static Wait Wait(float seconds) { return new Wait(seconds); }        public static Trigger Trigger(Animator animator, string name, bool set = true) { return new Trigger(animator, name, set); }        public static WaitForAnimatorState WaitForAnimatorState(Animator animator, string name, int layer = 0) { return new WaitForAnimatorState(animator, name, layer); }        public static SetBool SetBool(Animator animator, string name, bool value) { return new SetBool(animator, name, value); }        public static SetActive SetActive(GameObject gameObject, bool active) { return new SetActive(gameObject, active); }        public static WaitForAnimatorSignal WaitForAnimatorSignal(Animator animator, string name, string state, int layer = 0) { return new WaitForAnimatorSignal(animator, name, state, layer); }        public static Terminate Terminate() { return new Terminate(); }        public static Log Log(string msg) { return new Log(msg); }        public static RandomSequence RandomSequence(int[] weights = null) { return new BTAI.RandomSequence(weights); }    }    /// <summary>    /// 节点抽象类    /// </summary>    public abstract class BTNode    {        public abstract BTState Tick();    }    /// <summary>    /// 包含子节点的组合 节点基类    /// </summary>    public abstract class Branch : BTNode    {        protected int activeChild;        protected List<BTNode> children = new List<BTNode>();        public virtual Branch OpenBranch(params BTNode[] children)        {            for (var i = 0; i < children.Length; i++)                this.children.Add(children[i]);            return this;        }        public List<BTNode> Children()        {            return children;        }        public int ActiveChild()        {            return activeChild;        }        public virtual void ResetChildren()        {            activeChild = 0;            for (var i = 0; i < children.Count; i++)            {                Branch b = children[i] as Branch;                if (b != null)                {                    b.ResetChildren();                }            }        }    }    /// <summary>    /// 装饰节点    只包含一个子节点,用于某种方式改变这个节点的行为    /// 比如过滤器(用于决定是否允许子节点运行的,如:Until Success, Until Fail等),这种节点的子节点应该是条件节点,条件节点一直检测“视线中是否有敌人”,知道发现敌人为止。    /// 或者 Limit 节点,用于指定某个子节点的最大运行次数    /// 或者 Timer节点,设置了一个计时器,不会立即执行子节点,而是等一段时间,时间到了开始执行子节点    /// 或者 TimerLimit节点,用于指定某个子节点的最长运行时间。    /// 或者 用于产生某个返回状态,    /// </summary>    public abstract class Decorator : BTNode    {        protected BTNode child;        public Decorator Do(BTNode child)        {            this.child = child;            return this;        }    }    /// <summary>    /// 顺序节点 (从左到右依次执行所有子节点,只要子节点返回Success就继续执行后续子节点,直到遇到Failure或者Runing,     /// 停止后续执行,并把这个节点返回给父节点,只有它的所有子节点都是Success他才会向父节点返回Success)    /// </summary>    public class Sequence : Branch    {        public override BTState Tick()        {            var childState = children[activeChild].Tick();            switch (childState)            {                case BTState.Success:                    activeChild++;                    if (activeChild == children.Count)                    {                        activeChild = 0;                        return BTState.Success;                    }                    else                        return BTState.Continue;                case BTState.Failure:                    activeChild = 0;                    return BTState.Failure;                case BTState.Continue:                    return BTState.Continue;                case BTState.Abort:                    activeChild = 0;                    return BTState.Abort;            }            throw new System.Exception("This should never happen, but clearly it has.");        }    }    /// <summary>    /// 选择节点从左到右依次执行所有子节点 ,只要遇到failure就继续执行后续子节点,直到遇到一个节点返回Success或Running为止。向父节点返回Success或Running    /// 所有子节点都是Fail, 那么向父节点凡湖Fail    /// 选择节点 用来在可能的行为集合中选择第一个成功的。 比如一个试图躲避枪击的AI角色, 它可以通过寻找隐蔽点, 或离开危险区域, 或寻找援助等多种方式实现目标。    /// 利用选择节点,他会尝试寻找Cover,失败后在试图逃离危险区域。    /// </summary>    public class Selector : Branch    {        public Selector(bool shuffle)        {            if (shuffle)            {                var n = children.Count;                while (n > 1)                {                    n--;                    var k = Mathf.FloorToInt(Random.value * (n + 1));                    var value = children[k];                    children[k] = children[n];                    children[n] = value;                }            }        }        public override BTState Tick()        {            var childState = children[activeChild].Tick();            switch (childState)            {                case BTState.Success:                    activeChild = 0;                    return BTState.Success;                case BTState.Failure:                    activeChild++;                    if (activeChild == children.Count)                    {                        activeChild = 0;                        return BTState.Failure;                    }                    else                        return BTState.Continue;                case BTState.Continue:                    return BTState.Continue;                case BTState.Abort:                    activeChild = 0;                    return BTState.Abort;            }            throw new System.Exception("This should never happen, but clearly it has.");        }    }    /// <summary>    /// 行为节点  调用方法,或运行协程。完成实际工作, 例如播放动画,让角色移动位置,感知敌人,更换武器,播放声音,增加生命值等。    /// </summary>    public class Action : BTNode    {        System.Action fn;        System.Func<IEnumerator<BTState>> coroutineFactory;        IEnumerator<BTState> coroutine;        public Action(System.Action fn)        {            this.fn = fn;        }        public Action(System.Func<IEnumerator<BTState>> coroutineFactory)        {            this.coroutineFactory = coroutineFactory;        }        public override BTState Tick()        {            if (fn != null)            {                fn();                return BTState.Success;            }            else            {                if (coroutine == null)                    coroutine = coroutineFactory();                if (!coroutine.MoveNext())                {                    coroutine = null;                    return BTState.Success;                }                var result = coroutine.Current;                if (result == BTState.Continue)                    return BTState.Continue;                else                {                    coroutine = null;                    return result;                }            }        }        public override string ToString()        {            return "Action : " + fn.Method.ToString();        }    }    /// <summary>    /// 条件节点   调用方法,如果方法返回true则返回成功,否则返回失败。    /// 用来测试当前是否满足某些性质或条件,例如“玩家是否在20米之内?”“是否能看到玩家?”“生命值是否大于50?”“弹药是否足够?”等    /// </summary>    public class Condition : BTNode    {        public System.Func<bool> fn;        public Condition(System.Func<bool> fn)        {            this.fn = fn;        }        public override BTState Tick()        {            return fn() ? BTState.Success : BTState.Failure;        }        public override string ToString()        {            return "Condition : " + fn.Method.ToString();        }    }    /// <summary>    /// 当方法为True的时候 尝试执行当前  子节点    /// </summary>    public class ConditionalBranch : Block    {        public System.Func<bool> fn;        bool tested = false;        public ConditionalBranch(System.Func<bool> fn)        {            this.fn = fn;        }        public override BTState Tick()        {            if (!tested)            {                tested = fn();            }            if (tested)            {                // 当前子节点执行完就进入下一个节点(超上限就返回到第一个)                var result = base.Tick();                // 没执行完                if (result == BTState.Continue)                    return BTState.Continue;                else                {                    tested = false;                    // 最后一个子节点执行完,才会为Ture                    return result;                }            }            else            {                return BTState.Failure;            }        }        public override string ToString()        {            return "ConditionalBranch : " + fn.Method.ToString();        }    }    /// <summary>    /// While节点   只要方法  返回True 就执行所有子节点, 否则返回 Failure    /// </summary>    public class While : Block    {        public System.Func<bool> fn;        public While(System.Func<bool> fn)        {            this.fn = fn;        }        public override BTState Tick()        {            if (fn())                base.Tick();            else            {                //if we exit the loop                ResetChildren();                return BTState.Failure;            }            return BTState.Continue;        }        public override string ToString()        {            return "While : " + fn.Method.ToString();        }    }    /// <summary>    /// 阻塞节点  如果当前子节点是Continue 说明没有执行完,阻塞着,执行完之后在继续它后面的兄弟节点 不管成功失败。    /// 如果当前结点是最后一个节点并执行完毕,说明成功!否则就是处于Continue状态。     /// 几个基本上是抽象节点, 像是让所有子节点都执行一遍, 当前子节点执行完就进入下一个节点(超上限就返回到第一个)    /// </summary>    public abstract class Block : Branch    {        public override BTState Tick()        {            switch (children[activeChild].Tick())            {                case BTState.Continue:                    return BTState.Continue;                default:                    activeChild++;                    if (activeChild == children.Count)                    {                        activeChild = 0;                        return BTState.Success;                    }                    return BTState.Continue;            }        }    }    public class Root : Block    {        public bool isTerminated = false;        public override BTState Tick()        {            if (isTerminated) return BTState.Abort;            while (true)            {                switch (children[activeChild].Tick())                {                    case BTState.Continue:                        return BTState.Continue;                    case BTState.Abort:                        isTerminated = true;                        return BTState.Abort;                    default:                        activeChild++;                        if (activeChild == children.Count)                        {                            activeChild = 0;                            return BTState.Success;                        }                        continue;                }            }        }    }    /// <summary>    /// 多次运行子节点(一个子节点执行一次就算一次)    /// </summary>    public class Repeat : Block    {        public int count = 1;        int currentCount = 0;        public Repeat(int count)        {            this.count = count;        }        public override BTState Tick()        {            if (count > 0 && currentCount < count)            {                var result = base.Tick();                switch (result)                {                    case BTState.Continue:                        return BTState.Continue;                    default:                        currentCount++;                        if (currentCount == count)                        {                            currentCount = 0;                            return BTState.Success;                        }                        return BTState.Continue;                }            }            return BTState.Success;        }        public override string ToString()        {            return "Repeat Until : " + currentCount + " / " + count;        }    }    /// <summary>    /// 随机的顺序  执行子节点     /// </summary>    public class RandomSequence : Block    {        int[] m_Weight = null;        int[] m_AddedWeight = null;        /// <summary>        /// 每次再次触发时,将选择一个随机子节点        /// </summary>        /// <param name="weight">保留null,以便所有子节点具有相同的权重。        /// 如果权重低于子节点, 则后续子节点的权重都为1</param>        public RandomSequence(int[] weight = null)        {            activeChild = -1;            m_Weight = weight;        }        public override Branch OpenBranch(params BTNode[] children)        {            m_AddedWeight = new int[children.Length];            for (int i = 0; i < children.Length; ++i)            {                int weight = 0;                int previousWeight = 0;                if (m_Weight == null || m_Weight.Length <= i)                {//如果没有那个权重, 就将权重 设置为1                    weight = 1;                }                else                    weight = m_Weight[i];                if (i > 0)                    previousWeight = m_AddedWeight[i - 1];                m_AddedWeight[i] = weight + previousWeight;            }            return base.OpenBranch(children);        }        public override BTState Tick()        {            if (activeChild == -1)                PickNewChild();            var result = children[activeChild].Tick();            switch (result)            {                case BTState.Continue:                    return BTState.Continue;                default:                    PickNewChild();                    return result;            }        }        void PickNewChild()        {            int choice = Random.Range(0, m_AddedWeight[m_AddedWeight.Length - 1]);            for (int i = 0; i < m_AddedWeight.Length; ++i)            {                if (choice - m_AddedWeight[i] <= 0)                {                    activeChild = i;                    break;                }            }        }        public override string ToString()        {            return "Random Sequence : " + activeChild + "/" + children.Count;        }    }    /// <summary>    /// 暂停执行几秒钟。    /// </summary>    public class Wait : BTNode    {        public float seconds = 0;        float future = -1;        public Wait(float seconds)        {            this.seconds = seconds;        }        public override BTState Tick()        {            if (future < 0)                future = Time.time + seconds;            if (Time.time >= future)            {                future = -1;                return BTState.Success;            }            else                return BTState.Continue;        }        public override string ToString()        {            return "Wait : " + (future - Time.time) + " / " + seconds;        }    }    /// <summary>    /// 设置动画  trigger 参数    /// </summary>    public class Trigger : BTNode    {        Animator animator;        int id;        string triggerName;        bool set = true;        //如果 set == false, 则重置trigger而不是设置它。        public Trigger(Animator animator, string name, bool set = true)        {            this.id = Animator.StringToHash(name);            this.animator = animator;            this.triggerName = name;            this.set = set;        }        public override BTState Tick()        {            if (set)                animator.SetTrigger(id);            else                animator.ResetTrigger(id);            return BTState.Success;        }        public override string ToString()        {            return "Trigger : " + triggerName;        }    }    /// <summary>    /// 设置动画 boolean 参数    /// </summary>    public class SetBool : BTNode    {        Animator animator;        int id;        bool value;        string triggerName;        public SetBool(Animator animator, string name, bool value)        {            this.id = Animator.StringToHash(name);            this.animator = animator;            this.value = value;            this.triggerName = name;        }        public override BTState Tick()        {            animator.SetBool(id, value);            return BTState.Success;        }        public override string ToString()        {            return "SetBool : " + triggerName + " = " + value.ToString();        }    }    /// <summary>    /// 等待animator达到一个状态。    /// </summary>    public class WaitForAnimatorState : BTNode    {        Animator animator;        int id;        int layer;        string stateName;        public WaitForAnimatorState(Animator animator, string name, int layer = 0)        {            this.id = Animator.StringToHash(name);            if (!animator.HasState(layer, this.id))            {                Debug.LogError("The animator does not have state: " + name);            }            this.animator = animator;            this.layer = layer;            this.stateName = name;        }        public override BTState Tick()        {            var state = animator.GetCurrentAnimatorStateInfo(layer);            if (state.fullPathHash == this.id || state.shortNameHash == this.id)                return BTState.Success;            return BTState.Continue;        }        public override string ToString()        {            return "Wait For State : " + stateName;        }    }    /// <summary>    /// 设置 GameObject 的激活状态    /// </summary>    public class SetActive : BTNode    {        GameObject gameObject;        bool active;        public SetActive(GameObject gameObject, bool active)        {            this.gameObject = gameObject;            this.active = active;        }        public override BTState Tick()        {            gameObject.SetActive(this.active);            return BTState.Success;        }        public override string ToString()        {            return "Set Active : " + gameObject.name + " = " + active;        }    }    /// <summary>    /// 等待animator从SendSignal状态机行为 接收信号。   SendSignal : StateMachineBehaviour    /// </summary>    public class WaitForAnimatorSignal : BTNode    {        // 进入或退出动画都为 False, 只有执行中为True        internal bool isSet = false;        string name;        int id;        public WaitForAnimatorSignal(Animator animator, string name, string state, int layer = 0)        {            this.name = name;            this.id = Animator.StringToHash(name);            if (!animator.HasState(layer, this.id))            {                Debug.LogError("The animator does not have state: " + name);            }            else            {                SendSignal.Register(animator, name, this);            }        }        public override BTState Tick()        {            if (!isSet)                return BTState.Continue;            else            {                isSet = false;                return BTState.Success;            }        }        public override string ToString()        {            return "Wait For Animator Signal : " + name;        }    }    /// <summary>    /// 终止节点  切换到中止 状态    /// </summary>    public class Terminate : BTNode    {        public override BTState Tick()        {            return BTState.Abort;        }    }    /// <summary>    /// Log  输出Log 的节点    /// </summary>    public class Log : BTNode    {        string msg;        public Log(string msg)        {            this.msg = msg;        }        public override BTState Tick()        {            Debug.Log(msg);            return BTState.Success;        }    }}#if UNITY_EDITORnamespace BTAI{    public interface IBTDebugable    {        Root GetAIRoot();    }}#endif
using BTAI;using System.Collections.Generic;using UnityEditor;using UnityEngine;namespace Gamekit2D{    /// <summary>    /// 运行是查看  行为树中所有节点的状态     /// </summary>    public class BTDebug : EditorWindow    {        protected BTAI.Root _currentRoot = null;        [MenuItem("Kit Tools/Behaviour Tree Debug")]        static void OpenWindow()        {            BTDebug btdebug = GetWindow<BTDebug>();            btdebug.Show();        }        private void OnGUI()        {            if (!Application.isPlaying)            {                EditorGUILayout.HelpBox("Only work during play mode.", MessageType.Info);            }            else            {                if (_currentRoot == null)                    FindRoot();                else                {                    RecursiveTreeParsing(_currentRoot, 0, true);                }            }        }        void Update()        {            Repaint();        }        void RecursiveTreeParsing(Branch branch, int indent, bool parentIsActive)        {            List<BTNode> nodes = branch.Children();            for (int i = 0; i < nodes.Count; ++i)            {                EditorGUI.indentLevel = indent;                bool isActiveChild = branch.ActiveChild() == i;                GUI.color = (isActiveChild && parentIsActive) ? Color.green : Color.white;                EditorGUILayout.LabelField(nodes[i].ToString());                if (nodes[i] is Branch)                    RecursiveTreeParsing(nodes[i] as Branch, indent + 1, isActiveChild);            }        }        void FindRoot()        {            if (Selection.activeGameObject == null)            {                _currentRoot = null;                return;            }            IBTDebugable debugable = Selection.activeGameObject.GetComponentInChildren<IBTDebugable>();            if (debugable != null)            {                _currentRoot = debugable.GetAIRoot();            }        }    }}

就是在菜单“Kit Tools/Behaviour Tree Debug" 可以查看TestBT.cs 对象所在行为树

20180725205404956.png

相关推荐:

使用C/C++编写PHP Extension

【c#教程】C# 数据类型

视频:C# 教程

更多相关文章

  1. Unity 3D 浅谈Shader 运行时状态及渲染模式遇到的问题
  2. go语言如何删除链表节点
  3. java对XML文件的解析、节点的增加、删除操作总结
  4. XML(4)XDocument和XmlDocument搜索指定的节点
  5. xml学习(7) .net 获取xml节点或者属性最大值
  6. FireFox对XML的处理兼容IE的节点处理方法
  7. 读写xml所有节点个人小结 和 读取xml节点的数据总结
  8. 详解XML命名空间(XML Namespaces)介绍以及节点读取方法的示例代码
  9. xml创建根节点、子节点的示例代码分享

随机推荐

  1. 注册中心 Eureka 源码解析 —— 项目结构
  2. 注册中心 Eureka 源码解析 —— Eureka-C
  3. 分布式事务 TCC-Transaction 源码分析 —
  4. Spring Cloud Feign的两种使用姿势
  5. 分布式事务 TCC-Transaction 源码分析 —
  6. 注册中心 Eureka 源码解析 —— Eureka-S
  7. 分布式事务 TCC-Transaction 源码分析 —
  8. 注册中心 Eureka 源码解析 —— Eureka-C
  9. 网关 Spring-Cloud-Gateway 源码解析 —
  10. 刚入门学习GO语言需要注意什么?有哪些框