行为树(BehaviorTree )的实现与应用

news/2025/1/13 2:35:55/文章来源:https://www.cnblogs.com/CloverJoyi/p/18667693

前言

我最近学习使用C#脚本实现Unity行为树,并使用行为树实现了对“空洞骑士”中,“假骑士”的AI行为逻辑的简单实现。本文主要记录了在这个过程中的一些要点。

行为树的原理及实现教程来自这位大佬的博客:
游戏AI行为决策——Behavior Tree(行为树)

一、运作逻辑

行为树的运作逻辑在大佬的博客中有详细说明,这里为了方便我自己查阅,就简单描述一下。

与状态机(FSM)不同,状态机的原理是停留在某一状态,重复执行该状态的逻辑,直到达成条件转换为别的状态;而行为树是不断从根节点向下搜索(根节点驱动),找到达成条件的节点执行,执行完成后重新从跟节点开始,一直重复这个过程。

行为树顾名思义是一个树状结构,它具有树状结构的特点,开发者可以灵活地进行组装,实现节点的重复利用,避免写重复的代码,提高了开发效率。其缺点可能就是每次都要从根节点重新遍历,性能开销和复杂性略大于有限状态机。

行为树的节点类型包含以下几种:

  1. 组合节点(Composite),指有多个子节点的特殊节点,具体包括:
    1. 顺序器(Sequence)
    2. 选择器(Selector)
    3. 并行器(Parallel)
    4. 过滤器(Filter)
    5. 主动选择器(ActiveSelector)
    6. 监视器(Monitor)
  2. 修饰节点(Decorator),指仅有一个子节点的特殊节点,具体包括:
    1. 取反器(Inverter)
    2. 重复执行器(Repeat)
  3. 动作节点,指可以自定义的节点,比如「攻击」、「巡视」之类的

树形结构的实现则是采用链表和栈,利用链表按顺序记录节点的所有子节点,利用栈暂时记录根节点便于调用。

具体的实现代码在大佬的博客中有详细代码,这里不多赘述,为了方便理解这里贴出我在学习后整理出的类图

(最后所有的节点都会聚合到BehaviorTreeBuilder中统一调用,类图中为了美观没有一一连线)

二、行为树的应用

行为树一般用于实现AI行为逻辑,我使用了我半年前用有限状态机制作的一个空洞骑士假骑士boss战的一个项目进行行为树应用练习,将假骑士的有限状态机更改为行为树

1. 设计行为树

在没有可视化的情况下,构建一个行为树还是比较复杂的,容易混乱,建议先像我这样将树形结构画出来,对照着图一步步构建。

我计划使用顺序器(Sequence)和选择器(Selector)组合以实现这个行为树。根据行为树和组合节点的特点:

选择节点会依次遍历检查它的子树,如果有一个子树成功执行就会返回成功并停止遍历,执行完成后重新从头开始

顺序节点会依次遍历检查它的子树,如果有一个节点执行失败就会返回失败并停止遍历,然后重新从头开始

我们可以将执行节点的条件(上图中连接线上的语句)单独作为节点放在行为节点前。按照这个思路,我将行为树的模拟图进行细化

蓝色的节点为条件节点,我又加了攻击和追击的cd判定,防止怪物不停的追着玩家或者不停的攻击。

利用选择节点从左到右依次检查的特性,我将待机节点放在最后,这样就不用为待机加条件节点了,前面的的节点如果都没有达成运行条件,就会运行待机。

2.节点实现

对于行为节点的实现,我相信大家各有各的手段,我就不展示我杂乱且业余的的代码了。这里主要说以下cd判定节点的实现。cd计时器我使用了协程,当可执行标记为true时进入协程并返回success,协程中将标记置为false,并在cd时间(我设置为5秒)后将标记置为true。

代码很简单,但是问题在于开启协程的方法StartCoroutine()只能在继承了MonoBehavior的类中使用,而cd判定节点必须继承自Behavior,且C#不支持多继承。

最后从网上找到大佬的解决办法。在场景中创建一个空物体(MonoStub),然后在空物体上挂载一个继承自MonoBehavior的空脚本MONOStub.cs ,最后利用MonoStubTemp.GetComponent<MONOStub>().StartCoroutine());语句调用StartCoroutine();

完整脚本在这里:

using System.Collections;  
using UnityEngine;  public class CDNode : Behavior{  private float cd;  private bool isCoolingDown;  public CDNode(float cd){  this.cd = cd;  this.isCoolingDown = false;  }  protected override EStatus OnUpdate(){  if (isCoolingDown)  return EStatus.Failure;  MStartCoroutine();  return EStatus.Success;  }  private void MStartCoroutine(){  GameObject MonoStubTemp = GameObject.Find("MonoStub");  if (MonoStubTemp == null){  MonoStubTemp = new GameObject();  MonoStubTemp.name = "MonoStub";  MonoStubTemp.AddComponent<MONOStub>();  }  MonoStubTemp.GetComponent<MONOStub>().StartCoroutine(CoolDown(cd));  //Debug.Log("开始计时器协程");  }  IEnumerator CoolDown(float cd){  isCoolingDown = true;  yield return new WaitForSeconds(cd);  isCoolingDown = false;  }}  public partial class BehaviorTreeBuilder{  public BehaviorTreeBuilder CDNode(float cd){  var node = new CDNode(cd);  AddBehavior(node);  return this;  }}

3.构建树

构建树就比较简单了,参照模拟图按部就班的写就行,这里我学着大佬写的有层次一点

private void BuildTree(){  builder.Seletctor()  .Sequence()  .DeidTrigger()  .Died(anim, rb)  .Back() .Sequence()  .SkillTrigger()  .ChangeDirection(rb)  .Skill(anim, rb)  .Back() .Sequence()  .CDNode(5)  .AttackTrigger(rb)  .ChangeDirection(rb)  .Attack(rb, anim)  .Back()  .Sequence()  .CDNode(5)  .WatchTrigger(rb)  .ChangeDirection(rb)  .Track(rb, anim)  .ChangeDirection(rb)  .Back()  .Sequence()  .Idle(anim)  .Back()  .End();  
}

将这个方法放在start()中运行,然后将builder.TreeTick();放在Update()中即可

private void Start(){  BuildTree();  
}  private void Update(){  builder.TreeTick();  
}

三、总结

相比于有限状态机,行为树在实现较为复杂的AI逻辑时具有很大的优势,行为节点和条件节点的组合使用极大地提升了代码的复用性,也使一些多阶段动作的实现更容易了。

那么之后我应该会去继续学习分层任务网络(HTN),据说是比行为树更先进一些,学习更先进更高级的东西使我快乐。

最终效果演示:使用行为树重新设计假骑士的行为逻辑_哔哩哔哩_bilibili

项目源码:使用行为树重新设计假骑士的行为逻辑_哔哩哔哩_bilibili

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/868458.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

48. django下载与基本使用

1.版本 django1.x:默认不支持异步 django2.x:默认不支持异步 django3.x:自带异步功能 2. 下载 2.1 pip安装pip install django==3.2.122.2 安装注意事项 计算机名称不能出现中文 注意python解释器版本与django版本的兼容性 项目中的文件名称不能出现中文 多个项目文件尽量不…

互联网不景气了那就玩玩嵌入式吧,用纯.NET开发并制作一个智能桌面机器人(一):从.NET IoT入门开始

前言 为什么我会想着制作一个智能桌面机器人呢?自问自答一下,看过我之前文章的小伙伴应该都知道我之前有为稚晖君开源的ElectronBot桌面机器人开发过一个桌面上位机软件叫电子脑壳,由于ElectronBot桌面机器人必须连接电脑才能使用,所以限制比较多,网友又对独立版本的桌面机…

C#进阶-在Ubuntu上部署ASP.NET Core Web API应用

随着云计算和容器化技术的普及,Linux 服务器已成为部署 Web 应用程序的主流平台之一。ASP.NET Core 作为一个跨平台、高性能的框架,非常适合在 Linux 环境中运行。本篇博客将详细介绍如何在 Linux 服务器上部署 ASP.NET Core Web API 应用,包括部署准备、应用发布、配置反向…

【CodeForces训练记录】Codeforces Round 996 (Div. 2)

训练情况赛后反思 开局连WA就知道这把完蛋了,应该要掉大分了,A题没考虑清楚,B题犯傻了一时间没看出来结论 A题 当且仅当两个人贴贴的时候,轮到谁走谁就输,后手可以把先手逼到两边,如果两人之间有一段距离,两人都必须往中间靠,如果两个人都往同一边走距离不变为无效操作…

2025 特斯拉 焕新 Model Y 增减配置详细参数对比分析图解 All In One

2025 特斯拉 焕新 Model Y 增减配置详细参数对比分析图解 All In One2025 特斯拉 焕新 Model Y 增减配置详细参数对比分析图解 All In One 焕新 Model Y 增配风阻降低到 0.22 Cd ✅ 车身变长到 4797 mm ✅ 车头保险杠新增一颗摄像头 ✅ 新增前排座椅通风 ✅ 新增后排座椅电动折…

Kernel Memory 让 SK 记住更多内容

Kernel Memory (KM) 是一种多模态 AI 服务,专注于通过自定义的连续数据混合管道高效索引数据集。它支持检索增强生成(RAG)、合成记忆、提示工程以及自定义语义记忆处理。KM 支持自然语言查询,从已索引的数据中获取答案,并提供完整的引用和原始来源链接。 通过 KM 我们可以…

大普时钟模块(Clock Module)

时钟模块(Clock Module) 同步精度高、保持能力强、温度稳定度高、频率准确度高、短稳性能强。 CM11T系列时钟模块,内置TCXO、超宽温,同步精度50ns CM55、CM22系列时钟模块,内置OCXO、超高精度 CM30系列时钟模块,内置OCXO、高频低噪 CM66系列时钟模块,内置OCXO+GNSS接收机 …

《CPython Internals》阅读笔记:p97-p117

《CPython Internals》学习第 7 天,p97-p117 总结,总计 21 页。 一、技术总结 1.词法分析(lexical analysis) 根据《Compilers-Principles, Techniques, and Tools》(《编译原理》第2版)第 5 页:The first phase of a compiler is called lexical analysis or scanning. T…

Qwen2ForSequenceClassification文本分类实战和经验分享

本文主要使用Qwen2ForSequenceClassification实现文本分类任务。 文章首发于我的知乎:https://zhuanlan.zhihu.com/p/17468021019 一、实验结果和结论 这几个月,在大模型分类场景做了很多实验,攒了一点小小经验。 1、短文本 1)query情感分类,一般不如BERT ps:结论和,htt…

Ubuntu22.04 解决 E: 无法定位软件包 yum

1、修改 sudo vim /etc/apt/sources.list的内容,将下文内容增加至该文件中:deb http://archive.ubuntu.com/ubuntu/ trusty main universe restricted multiverse# 默认注释了源码镜像以提高 apt update 速度,如有需要可自行取消注释 deb https://mirrors.tuna.tsinghua.edu…

【安全运营】第6年实践总结

一、安全运营全景图 安全运营全景图调整的原因:一是公司在文化、部门、人员方面调整,导致有些部分不再适用;二是2024年针对安全运营规划开会讨论过多次,部分逻辑和内容有变化;三是安全运营工作范围有变化,需要进行合并、增加;四是经过2024年的实践,个人的观点有变化,需…

如何使用 Logstash 8 连接 Easysearch

背景 很多小伙伴都在使用 Logstash ,随着各家安全扫描、安全策略的加固,不少小伙伴已经开始使用 Logstash 8 了。在使用 Logstash 8 连接 Easysearch 的时候可能会遇到问题,比如下图。提示连接的不是兼容版本的 Elasticsearch 。 解决方法有两种 两种方法对 Logstash 和 Log…