How to Develop a Game
Behaviour Tree
PublishDate: 2025-06-01 | CreateDate: 2025-06-01 | LastModify: 2025-06-01 | Creator:ljf12825

Unity的行为树是一种常用于AI决策的结构,它在游戏开发中用于描述AI的行为和决策逻辑。它通过阻止一系列的节点来表示各种行为,树形结构的设计让它可以清晰地展示AI决策过程

基本概念

行为树的每个节点都有一个功能,它们通常分为以下几种类型

行为树的执行过程

行为树的执行是从根节点开始,逐层向下执行。它通常会根据子节点的状态(成功、失败或运行中)来决定接下来的执行路径

行为树的优势

Unity中行为树的实现

Unity中没有内建的行为树系统,但是可以使用一些现有的库来实现行为树,例如:

Unity ML-Agents

GitHub ML-Agents

ML-Agents (Machine Learning Agents)是由Unity官方提供的一款工具包,旨在帮助开发者在Unity中实现和训练智能体(Agents)使用机器学习算法。它为游戏和仿真环境中的AI提供了一种灵活的方式,利用强化学习、监督学习等技术来训练代理学习从环境中获得经验并做出决策

ML-Agents提供了基于PyTorch的算法实现,可以方便地使用其提供的Python API,通过强化学习、模仿学习、神经进化或任何其他方法训练智能代理

核心组件

ML-Agents的工作主要依赖于以下几个核心组件

机器学习的训练过程

ML-Agents的训练过程包括以下几个主要步骤:

  1. 设置环境:需要在Unity中创建一个合适的场景,设置Agent,并为Agent提供可观测的信息(如位置、速度、目标位置等)以及奖励机制(如击中目标、避开障碍物等)

  2. 定义Agent的行为:需要为Agent编写C#脚本,告诉它如何根据环境的状态选择动作。通常这会涉及到对传入的观测数据进行处理,并输出动作(例如移动、跳跃等)

  3. 训练Agent:通过ML-Agents中的Python接口,利用强化学习算法(如PPO、A3C、DDPG等)训练Agent。训练过程中,代理通过与环境的交互,逐步调整策略以最大化累积的奖励

  4. 评估与优化:训练过程中,可以定期评估Agent的表现,查看它是否能成功完成任务,并根据结果调整训练策略或优化环境设计

ML-Agents的主要特性

ML-Agent使用步骤

  1. 安装ML-Agents ML-Agents需要安装Unity插件和Python库
pip install mlagents
  1. 创建Agent 可以为Unity中的角色创建一个代理。代理需要实现如下接口
  1. 训练代理 通过Python训练脚本,可以开始训练代理。ML-Agents提供了一个命令行工具(mlagents-learn),可以通过它来启动训练
mlagents-learn config/trainer_config.yaml --run-id=first_run
  1. 使用模型 一旦训练完成,可以导出训练好的模型,并将其加载到Unity项目中,直接替换代理的行为逻辑

训练的算法与策略

ML-Agents支持多种强化学习算法

Behavior Designer

Behaviour Designer是一款强大的Unity插件,用于创建和管理行为树,它让开发者可以通过图形化界面设计复杂的AI行为,而不需要手动编写复杂的代码。Behaviour Designer的主要优势在于它提供了一种直观的方式来构建和调试AI的决策系统,同时支持强化学习和传统的AI算法

Behaviour Designer的核心功能

Behaviour Designer的使用

  1. 安装Behaviour Designer 通过Unity的Package Manager或Asset Store安装Behaviour Designer

  2. 创建Behaviour Tree 创建一个新的行为树

  1. 设计行为树 在Behavior Tree编辑器中,将看到一个空白的画布,可以通过拖拽不同的节点来创建和连接行为树,例如:

可以根据需要不断添加、调整和优化行为树

  1. 为Agent添加Behavior Tree 将设计好的行为树应用到Unity中的智能体(例如玩家、敌人或NPC)。需要为智能体添加Behavior Tree组件,选择刚才创建的行为树文件作为它的行为树源

  2. 调试与优化

  1. 动态修改行为 可以在游戏运行时动态地修改AI的行为树或更改黑板上的数据。例如,敌人可能会根据当前的血量调整攻击策略,或者根据玩家的行为做出反应。Behavior Designer允许实时修改黑板数据和行为树

行为树的设计技巧

Behavior Designer 高级功能

  1. 多线程执行 Behavior Designer支持在多个线程中并行执行不同的任务,使得行为树的性能更高,尤其是当AI行为复杂且需要处理多个任务时(如多个敌人同时行动)
  2. 事件驱动行为 可以设置一些事件(例如玩家进入攻击范围或触发特定的环境事件)来驱动AI行为树的切换,利用事件触发来灵活控制行为树的执行
  3. 条件与动作分离 行为树中的节点通常包括条件判断和实际行为(动作),Behavior Designer允许清晰地将两者分开,便于调试和维护。例如,AI的巡逻i行为可以与判断敌人是否在视野内的逻辑分开
  4. 内建的AI任务和动作 Behavior Designer包含了一些常用的AI任务和动作,如NavMesh移动、攻击、逃跑、等待等,可以大大简化开发过程

Unity Behavior

Manual Behavior

自定义行为树实现

自定义行为树的实现涉及到创建一套系统,用于描述和管理AI代理(Agent)和行为决策

行为树的主要目的是通过一个树形结构来描述AI的决策过程,其中节点表示AI可能的行为或决策,根节点从树的顶端开始,逐层向下执行

  1. 设计行为树的基本结构 行为树的核心概念包括以下几种节点类型
  1. 定义行为树节点接口 定义一个抽象的节点类BTNode,所有的行为树节点都将继承自这个类
using System;
using System.Collections.Generic;
using UnityEngine;

public enum NodeState
{
    SUCCESS,
    FAILURE,
    RUNNING
}

// 定义行为树节点接口
public abstract class BTNode
{
    public NodeState state;
    
    public abstract NodeState Execute();
}
  1. Selector实现 选择节点的作用是依次检查每个子节点,只要有一个子节点成功,它就会返回成功。否则,返回失败
public class SelectorNode : BTNode
{
    private List<BTNode> children = new List<BTNode>();

    public void AddChild(BTNode child) => children.Add(child);

    public override NodeState Execute()
    {
        foreach (var child in children)
        {
            state = child.Execute();
            if (state == NodeState.SUCCESS)
                return NodeState.SUCCESS;
        }
        return NodeState.FAILURE;
    }
}
  1. Sequence实现 序列节点是按顺序依次执行其子节点,直到一个子节点失败,或者所有子节点执行成功
public class SequenceNode : BTNode
{
    private List<BTNode> children = new List<BTNode>();

    public void AddChild(BTNode child) => children.Add(child);

    public override NodeState Execute()
    {
        foreach (var child in children)
        {
            state = child.Execute();
            if (state == NodeState.FAILURE)
                return NodeState.FAILURE;
        }
        return NodeState.SUCCESS;
    }
}
  1. Action实现 动作节点是叶子节点,执行具体的行为(如移动、攻击等)
public class ActionNode : BTNode
{
    private Func<NodeState> action;

    public ActionNode(Func<NodeState> action) => this.action = action;

    public override NodeState Execute() => action.Invoke();
}
  1. Condition实现 条件节点用于判断某个条件是否成立。例如,检测敌人是否在视野内
public class ConditionNode : BTNode
{
    private Func<bool> condition;

    public ConditionNode(Func<bool> condition) => this.condition = condition;

    public override NodeState Execute() => condition.Invoke() ? NodeState.SUCCESS : NodeState.FAILURE;
}
  1. 构建行为树 现在可以构建一个行为树,假设想要实现一个简单的敌人AI
  2. 如果敌人被发现,攻击敌人
  3. 如果敌人不在视野内,继续巡逻
public class EnemyAI : MonoBehaviour
{
    private BTNode behaviourTree;

    void Start()
    {
        // 创建行为树节点
        SelectorNode root = new SelectorNode();

        // 创建条件节点:检查敌人是否在视野内
        ConditionNode enemyInSight = new ConditionNode(() => IsEnemyInSight());

        // 创建动作节点:执行攻击
        ActionNode attackEnemy = new ActionNode(() => 
        {
            Attack();
            return NodeState.SUCCESS;
        });

        // 创建序列节点:敌人被发现 -> 攻击
        SequenceNode sequence = new SequenceNode();
        sequence.AddChild(enemyInSight);
        sequence.AddChild(attackEnemy);

        // 将选择节点作为根节点
        root.AddChild(sequence);

        // 行为树
        behaviorTree = root;
    }

    void Update()
    {
        // 执行行为树
        behaviorTree.Execute();
    }

    bool IsEnemyInSight()
    {
        // 假设简单的视野检测,返回随机值
        return UnityEngine.Random.value > 0.5f;
    }

    void Attack()
    {
        Debug.Log("Attacking the enemy!");
    }
}

调试与优化
在基本的行为树结构上,接下来可以

扩展与优化\