码迷,mamicode.com
首页 > 其他好文 > 详细

简单版行为树(BehaviorTree)实现

时间:2018-09-27 01:44:13      阅读:1079      评论:0      收藏:0      [点我收藏+]

标签:virt   fail   sele   node   running   success   rri   var   enum   

简单版行为树(BehaviorTree)实现


接触到的第一个游戏AI制作方法就是行为树,我们游戏要做机器人,所以学以致用,实现了一个简单版的行为树.

行为树

行为树主要包含两类节点,一类是叶子节点:主要作用是实现功能;一类是复合节点:主要作用是控制.

行为树就是通过对不同的叶子节点进行组合后来达到AI控制效果的,每个叶子节点都会向其父节点报告执行状态,父节点再根据自己的逻辑改变自身状态,如此向上递归则可知整个行为树的状态.

叶子节点

- 动作节点:执行到此节点时,会执行一个动作,执行后返回执行成功.
- 条件节点:执行到此节点时,会进行条件判断,若条件判断成功返回执行成功否则返回执行失败.
- 等待节点:一般实现为执行到此节点时,会等待一段时间,若未超出等待时间则返回执行中,若超出等到时间则返回执行成功

复合节点

- 序列节点:执行到此节点时,会依次执行其子节点,若有子节点返回执行中,则其状态也为执行中,并等待该子节点执行完毕,若有子节点执行失败,其状态也为执行失败,若所有子节点执行成功,则其状态也为执行成功(相当于&).)
- 选择节点:执行到此节点时,会依次执行其子节点,若有子节点返回执行中,则其状态也为执行中,并等待该自己点执行完毕.若有子节点执行成功,其状态也为执行成功,若所有子节点执行失败,则其状态为执行失败(相当于|).
- 并行节点:

以上就是行为树的几种基本节点

具体代码


   public enum NodeType
    {
        Action
      , Condition
      , Wait
      , Sequence
      , Select
    }

    public enum NodeState
    {
        Ready
      , Running
      , Success
      , Failed
    }

    public class BehaviorTree
    {
        private readonly BtNode    _rootNode;
        private BtNode    _runingNode;
        public  NodeState State { get; private set; }

        public BehaviorTree(BtNode root)
        {
            _rootNode = root;
            State     = NodeState.Ready;
        }

        public NodeState Update()
        {
            State = _rootNode.OnVisit();
            return State;
        }

        public void Reset()
        {
            _rootNode.Reset();
        }
    }

    #region 节点定义

    public abstract class BtNode
    {
        public NodeType  Type  { get; private set; }
        public NodeState State { get; protected set; }

        protected BtNode(NodeType nodeType)
        {
            State = NodeState.Ready;
            Type  = nodeType;
        }

        public abstract NodeState OnVisit();

        public virtual void Reset()
        {
            State = NodeState.Ready;
        }
    }

    public abstract class BtCompostieNode : BtNode
    {
        protected List<BtNode> ChildNodes;

        protected BtCompostieNode(List<BtNode> nodes, NodeType nodeType) : base(nodeType)
        {
            ChildNodes = nodes ?? new List<BtNode>();
        }

        public virtual BtCompostieNode AddChild(BtNode node)
        {
            ChildNodes.Add(node);
            return this;
        }
    }

    #region 叶子节点

    // 动作节点
    public class ActionNode : BtNode
    {
        private readonly Action _action;

        public ActionNode(Action action) : base(NodeType.Action)
        {
            _action = action;
        }

        public override NodeState OnVisit()
        {
            _action?.Invoke();
            return NodeState.Success;
        }
    }

    // 条件节点
    public class ConditionNode : BtNode
    {
        private readonly Func<bool> _checkFunc;

        public ConditionNode(Func<bool> checkFunc) : base(NodeType.Condition)
        {
            _checkFunc = checkFunc;
        }

        public override NodeState OnVisit()
        {
            if (_checkFunc == null)
                return NodeState.Success;

            return _checkFunc.Invoke() ? NodeState.Success : NodeState.Failed;
        }
    }

    // 等待节点
    public class WaitNode : BtNode
    {
        private readonly int  _waitSec;
        private          long _startSec;

        public WaitNode(int waitSec) : base(NodeType.Wait)
        {
            _waitSec = waitSec;
        }

        public override NodeState OnVisit()
        {
            if (_startSec == 0)
            {
                _startSec = DateTime.Now.Ticks / TimeSpan.TicksPerSecond;
                State     = NodeState.Running;
                Console.WriteLine(DateTime.Now.Ticks / TimeSpan.TicksPerSecond);
            }

            // 还没有到时间返回running
            if (DateTime.Now < new DateTime((_waitSec + _startSec) * TimeSpan.TicksPerSecond))
                return State;

            Console.WriteLine(DateTime.Now.Ticks / TimeSpan.TicksPerSecond);
            State = NodeState.Success;
            return State;
        }

        public override void Reset()
        {
            base.Reset();
            _startSec = 0;
        }
    }

    #endregion

    #region 复合节点

    public class SequenceNode : BtCompostieNode
    {
        public SequenceNode(List<BtNode> nodes = null) : base(nodes, NodeType.Sequence)
        {
        }

        public override NodeState OnVisit()
        {
            foreach (var node in ChildNodes)
            {
                var result = node.OnVisit();
                if (result != NodeState.Success)
                    return result;
            }

            return NodeState.Success;
        }
    }

    public class SelectNode : BtCompostieNode
    {
        public SelectNode(List<BtNode> nodes = null) : base(nodes, NodeType.Select)
        {
        }

        public override NodeState OnVisit()
        {
            foreach (var node in ChildNodes)
            {
                var result = node.OnVisit();
                if (result != NodeState.Failed)
                    return result;
            }

            return NodeState.Failed;
        }
    }

测试代码(有条件还是别手写行为树了,挺费劲的)

技术分享图片

简单版行为树(BehaviorTree)实现

标签:virt   fail   sele   node   running   success   rri   var   enum   

原文地址:https://www.cnblogs.com/Fallever/p/9710821.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!