unity行为树的简单实现

前言

行为树,英文是Behavior Tree,简称BT,是一棵用于控制 AI 决策行为的、包含了层级节点的树结构。 当我们要决策当前这个士兵要做什么样的行为的时候, 我们就会自顶向下的,通过一些条件来搜索这颗树,最终确定需要做的行为(叶节点),并且执行它 ,这就是行为树的基本原理。

正文
话不多说直接上代码,下面是第一个脚本。

using UnityEngine;

namespace MDD.AI {

    //声明一个枚举

    public enum NodeState
    {
        Successufully,
        Failure,
        Running
    }

    // 创建一个 抽象函数 供子类调用
    public abstract class BTNode 
    {
        public abstract NodeState Tick();
    }

    //

    public  abstract class BTBifurcate : BTNode
    {
        protected List<BTNode> ChildNode = new List<BTNode>();

        protected int currentChild = 0;
        /// <summary>
        /// 
        /// </summary>
        /// <param name="chlidNode">BTNode类型的任意多个参数</param>
        /// <returns></returns>
        public virtual BTBifurcate open(params BTNode [] chlidNode) 
        {
            for (int i = 0; i < chlidNode.Length; ++i)
            {
                ChildNode.Add(chlidNode[i]);
            }
            
            return this;
            
        }
    }


    /// <summary>
    ///  顺序节点,依次执行所有的子节点,当有一个子节点主执行失败的时候就不会继续执行后面的节点
    /// </summary>
    public class BTSequential : BTBifurcate
    {
        public override NodeState Tick()
        {
            var childNode = ChildNode[currentChild].Tick();

            switch (childNode) 
            {
                case NodeState.Successufully:
                    currentChild++;
                    if (currentChild == ChildNode.Count) {
                        currentChild = 0;
                    }
                    return NodeState.Successufully;
                case NodeState.Failure:
                    currentChild = 0;
                    return NodeState.Failure;
                case NodeState.Running:
                    return NodeState.Running;
            }
            return NodeState.Successufully;
        }
    }

    /// <summary>
    /// 选择节点,依次执行所有的节点, 只要有一个节点执行成功就不执行后续的节点了
    /// </summary>
    public class BTSelect : BTBifurcate
    {
        public override NodeState Tick()
        {
            var childNode = ChildNode[currentChild].Tick();

            switch (childNode)
            {
                case NodeState.Successufully:
                    currentChild = 0;
                    return NodeState.Successufully;
                case NodeState.Failure:
                    currentChild++;
                    if (currentChild == ChildNode.Count)
                    {
                        currentChild = 0;
                    }
                    return NodeState.Failure;
                case NodeState.Running:
                    return NodeState.Running;
            }
            return NodeState.Failure;
        }
    }
    //循环一直进行循环可以一直执行某一个行为知道条件改变
    public class BTLoopNode : BTBifurcate
    {
        public override NodeState Tick()
        {
            var childNode = ChildNode[currentChild].Tick();
            while (true) 
            {
                switch (childNode)
                {
                    case NodeState.Running:
                        return NodeState.Running;
                    default:
                        currentChild++;
                        if (currentChild == ChildNode.Count)
                        {
                            currentChild = 0;
                            return NodeState.Successufully;
                        }
                   continue;
                }
            }

        }
    }

// 条件
    public abstract class BTconditionNode : BTNode { }
//动作/行为
    public abstract class BTActionNode : BTNode { }
}

接下来是第二个脚本

using UnityEngine;
using MDD.AI;

public class BehaviourTree : MonoBehaviour
{
    protected BTLoopNode m_Root;

    protected virtual void Start()
    {
        m_Root = new BTLoopNode();
    }

    protected virtual void Update()
    {
        m_Root.Tick();
    }

    protected void AddNode(params BTNode[] child) 
    {
        m_Root.open(child);
    }
}

写到这里也就大致将行为树写完了,接下来是测试脚本。
在这里我准备了两个行为脚本和一个条件脚本。

using System;
using UnityEngine;
using MDD.AI;
public class BTAction_01 : BTActionNode
{
//行为脚本
   /// <summary>
    /// 把这个函数当作mono的一个动作
    /// </summary>
    /// <returns></returns>
    public override NodeState Tick()
    {
        OnAction();
        return NodeState.Successufully;
    }

    private void OnAction() 
    {
        Debug.Log("动作11");
    }
}
using System;
using UnityEngine;
using MDD.AI;


public class BTAction_02 : BTActionNode
{
 //行为脚本
    /// <summary>
    /// 把这个函数当作mono的一个动作
    /// </summary>
    /// <returns></returns>
    public override NodeState Tick()
    {
        OnAction();
        return NodeState.Successufully;
    }
    private void OnAction()
    {
        Debug.Log("动作22");
    }
}
using System;
using UnityEngine;
using MDD.AI;
public class BTconNode : BTconditionNode
{
//声明一个委托
    private Func<bool> func;

    public BTconNode(Func<bool> _func)
    {
        func = _func;
    }
    public override NodeState Tick()
    {
        if (func != null)
        {
            return (func.Invoke()) ? NodeState.Successufully : NodeState.Failure;
        }
        return NodeState.Failure;
    }
}

接下来就是正是的测试脚本了

using System;
using MDD.AI;
using UnityEngine;

public class TestBT : BehaviourTree
{

    public bool b;
    protected override void Start()
    {
        base.Start();

        AddNode(new BTSelect().open(new BTSequential().open(new BTconNode(testBool),new BTAction_01()),new BTAction_02()));
    }

    public bool testBool() 
    {
        Debug.Log("我是test");
        return b;
    }
}

可以在inspector上更改b的值来观察打印数值 以便更好的理解上述的简单的行为树。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值