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的值来观察打印数值 以便更好的理解上述的简单的行为树。

猜你喜欢

转载自blog.csdn.net/m0_52021450/article/details/129220051