AI决策算法 行为树实现(一)

本系列文章部分内容参考自 https://zhuanlan.zhihu.com/p/19890016?columnSlug=indiegamepixel 

感谢原作者的知识分享





行为树包括 :

基础节点:BaseNode

前置条件节点:PreconditionNode

顺序节点:SequenceNode

并行节点:ParallelNode ( 当一个节点不通过就不执行 )

并行节点2:ParallelFlexibleNode ( 当所有节点不通过才不执行 )

选择节点: PrioritySelectorNode

逻辑节点:ActionNode

数据提供者: DataBase

行为树: BTree


实现:


基础节点:BaseNode

namespace BehaviorTree
{
    public abstract class BaseNode
    {
        #region 字段
        public string name;
        protected List<BaseNode> children;     // 子节点
        public PreconditionNode precondition;  // 放行条件
        public DataBase database;              // 数据提供者
        public float intervalTime = 0;         // 冷却时间
        private float intervalTimer = 0;   
        public bool activated;                 // 是否激活过了
        #endregion

        #region 属性
        public List<BaseNode> Children { get { return children; } }

        //节点可行判断
        public bool Evaluate { get { return activated && CheckTimer() && (precondition == null || precondition.Check()) && DoEvaluate(); } }
        #endregion

        public BaseNode() : this(null) { }

        public BaseNode(PreconditionNode precondition) { this.precondition = precondition; }

        #region 接口
        /// <summary>
        /// 激活
        /// </summary>
        /// <param name="database"></param>
        public virtual void Activate(DataBase database)
        {
            if (activated)
                return;

            this.database = database;

            if (precondition != null)
                precondition.Activate(database);

            if (children != null)
                foreach (var n in children)
                    n.Activate(database);

            activated = true;
        }

        /// <summary>
        /// 个性化可行
        /// </summary>
        /// <returns></returns>
        protected virtual bool DoEvaluate() { return true; }

        /// <summary>
        /// 执行
        /// </summary>
        /// <returns></returns>
        public virtual NodeResult Tick() { return NodeResult.Ended; }

        public virtual void Clear() { }

        public virtual void AddChild(BaseNode node)
        {
            if (children == null)
                children = new List<BaseNode>();
            if (node != null)
                children.Add(node);
        }

        public virtual void RemoveChild(BaseNode node)
        {
            if (children != null && node != null && children.Contains(node))
                children.Remove(node);
        }

        /// <summary>
        /// 是否冷却完成
        /// </summary>
        /// <returns></returns>
        private bool CheckTimer()
        {
            //当前时间-刚才的时间=过去的时间
            if (Time.time - intervalTimer > intervalTime)
            {
                intervalTimer = Time.time;
                return true;
            }
            return false;
        }
        #endregion

    }

    /// <summary>
    /// 节点结果
    /// </summary>
    public enum NodeResult{
        Ended = 1,
        Running = 2
    }

}


前置条件节点:PreconditionNode

namespace BehaviorTree
{
    public abstract class PreconditionNode : BaseNode
    {
        public PreconditionNode() : base(null) { }

        /// <summary>
        /// 是否通过条件
        /// </summary>
        /// <returns></returns>
        public abstract bool Check();

        public override NodeResult Tick()
        {
            if (Check())
                return NodeResult.Ended;
            else
                return NodeResult.Running;
        }
    }
}


数据提供者: DataBase

namespace BehaviorTree
{
    /// <summary>
    /// 数据提供者
    /// </summary>
    public class DataBase : MonoBehaviour
    {
        private List<object> _database = new List<object>();      // 数据
        private List<string> _dataNames = new List<string>();     // 数据名

        #region 接口
        /// <summary>
        /// 根据数据名取得数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="dataName"></param>
        /// <returns></returns>
        public T GetData<T>(string dataName)
        {
            int dataId = IndexOfDataId(dataName);
            if (dataId == -1) Debug.LogError("Database: Data for " + dataName + " does not exist!");
            return (T)_database[dataId];
        }

        /// <summary>
        /// 根据ID取得数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="dataId"></param>
        /// <returns></returns>
        public T GetData<T>(int dataId)
        {
            return (T)_database[dataId];
        }

        /// <summary>
        /// 根据数据名设置数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="dataName"></param>
        /// <param name="data"></param>
        public void SetData<T>(string dataName, T data)
        {
            int dataId = GetDataId(dataName);
            _database[dataId] = (object)data;
        }

        /// <summary>
        /// 根据数据ID设置数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="dataId"></param>
        /// <param name="data"></param>
        public void SetData<T>(int dataId, T data)
        {
            _database[dataId] = (object)data;
        }

        /// <summary>
        /// 根据数据名取得数据ID
        /// </summary>
        /// <param name="dataName"></param>
        /// <returns></returns>
        public int GetDataId(string dataName)
        {
            int dataId = IndexOfDataId(dataName);
            if (dataId == -1)
            {
                _dataNames.Add(dataName);
                _database.Add(null);
                dataId = _dataNames.Count - 1;
            }

            return dataId;
        }

        private int IndexOfDataId(string dataName)
        {
            for (int i = 0; i < _dataNames.Count; i++)
            {
                if (_dataNames[i].Equals(dataName)) return i;
            }

            return -1;
        }

        public bool ContainsData(string dataName)
        {
            return IndexOfDataId(dataName) != -1;
        }
        #endregion

    }

}


逻辑节点:ActionNode

namespace BehaviorTree
{
    public class ActionNode : BaseNode
    {
        private ActionNodeState _status = ActionNodeState.Ready;

        public ActionNode(PreconditionNode precondition = null) : base(precondition) { }

        /// <summary>
        /// 进入节点触发
        /// </summary>
		protected virtual void Enter () {
			
		}

        /// <summary>
        /// 退出节点触发
        /// </summary>
		protected virtual void Exit () {
			
		}

        /// <summary>
        /// 节点执行中
        /// </summary>
        /// <returns></returns>
        protected virtual NodeResult Execute()
        {
            return NodeResult.Running;
        }

        public override void Clear()
        {
            if (_status != ActionNodeState.Ready)
            {	
                Exit();
                _status = ActionNodeState.Ready;
            }
        }

        public override NodeResult Tick()
        {
            NodeResult result = NodeResult.Ended;
            //进入
            if (_status == ActionNodeState.Ready)
            {
                Enter();
                _status = ActionNodeState.Running;
            }
            //运行
            if (_status == ActionNodeState.Running)
            {		
                result = Execute();
                //结束
                if (result != NodeResult.Running)
                {
                    Exit();
                    _status = ActionNodeState.Ready;
                }
            }
            return result;
        }

        public override void AddChild(BaseNode node)
        {
           
        }

        public override void RemoveChild(BaseNode node)
        {
            
        }

    }

    public enum ActionNodeState
    {
        Ready = 1,
        Running = 2
    }

}


行为树: BTree

namespace BehaviorTree
{
    public class BTree : MonoBehaviour
    {

        #region 字段
        protected BaseNode _root = null;       // 根节点

        [HideInInspector]
        public DataBase database;              // 数据提供者

        [HideInInspector]
        public bool isRunning = true;

        public const string RESET = "Rest";    // 重置宏
        private static int _resetId;
        #endregion

        #region Unity回调
        void Awake()
        {
            Init();

            //激活根节点
            _root.Activate(database);
        }

        void Update()
        {
            if (!isRunning) return;

            //判断是否需要重置
            if (database.GetData<bool>(RESET))
            {
                Reset();
                database.SetData<bool>(RESET, false);
            }

            //执行行为树
            if (_root.Evaluate)
            {
                _root.Tick();
            }
        }

        void OnDestroy()
        {
            if (_root != null)
            {
                _root.Clear();
            }
        }
        #endregion

        #region 接口
        /// <summary>
        /// 初始化数据提供者
        /// </summary>
        protected virtual void Init()
        {
            database = GetComponent<DataBase>();
            if (database == null)
            {
                database = gameObject.AddComponent<DataBase>();
            }

            _resetId = database.GetDataId(RESET);
            database.SetData<bool>(_resetId, false);
        }

        protected void Reset()
        {
            if (_root != null)
            {
                _root.Clear();
            }
        }
        #endregion 
    }

}




  • 3
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值