当前位置: 首页 > news >正文

行为树(Behavior Trees)

行为树(Behavior Trees)是一种在游戏开发中广泛使用的AI设计模式,主要用于描述AI的行为和决策过程,实现更加智能和自然的游戏AI。它由多个节点组成,每个节点代表一个行为或决策,按照特定的方式连接在一起,形成一个树状结构。
在行为树中,根节点是AI的起点,通过遍历子节点来决策AI的行为。节点有以下三种状态:成功(Success)、失败(Failure)和运行(Running)。前两个通知其父节点其操作是成功还是失败。第三种意味着尚未确定成功或失败,并且该节点仍在运行。下次树被选择时,该节点将再次被选择,此时它将再次有机会成功,失败或继续运行。
行为树的节点有以下几种主要原型:

  1. 组合控制节点(Composite):一种将多个子节点组合在一起的节点,用于实现复杂的行为和决策逻辑。主要包括次序节点(Sequencer)和选择节点(Selector)。次序节点并行执行多个子节点,直到所有子节点都返回成功或者任意一个子节点返回失败为止。选择节点按照顺序执行子节点,当某个子节点返回成功时,停止执行并返回成功。
    在这里插入图片描述
    在这里插入图片描述

  2. 修饰节点(Decorator):一种特殊的节点,它不执行具体的行为或决策,而是修饰其它节点的行为或决策。主要包括逆变节点(Inverter)和重复节点(Repeater)。逆变节点可以将子节点的结果倒转,比如子节点返回了失败,则这个修饰节点会向上返回成功,以此类推。重复节点重复执行其子节点指定的次数或者一直重复执行,直到其子节点返回成功或者失败。
    在这里插入图片描述
    在这里插入图片描述

  3. 叶节点(Leaf):树的最末端,就是这些AI实际上去做事情的命令。

行为树通过模拟树状结构来描述AI的行为和决策过程,使得AI的行为更加灵活、自然和智能。
代码实现
在这里插入图片描述

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using BehaviourTree;namespace BehaviourTree
{public class BehaviourTree : MonoBehaviour{private Node root = null;private Blackboard blackboard;public Node Root{get{return root;}set{root= value;}}void Start(){Init();}void Update(){if(root!=null&& gameObject!=null){root.Evaluate(gameObject.transform,blackboard);}}protected virtual void Init(){blackboard = new Blackboard();}}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using BehaviourTree;namespace BehaviourTree
{//行为树共享数据public class Blackboard{private Dictionary<string,object> Data;public Blackboard(){Data = new Dictionary<string, object>();}//获取数据public T Get<T>(string key){if(Data.ContainsKey(key)){return (T)Data[key];}return default;}//添加数据public void Add<T>(string key,T value){if(Data.ContainsKey(key)){Data[key] = value;}else{Data.Add(key,value);}}//删除数据public void Remove(string key){if(Data.ContainsKey(key)){Data.Remove(key);}else{Debug.Log("数据不存在 "+key);}}}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using BehaviourTree;namespace BehaviourTree
{//状态类型public enum Status{Running,    //运行中Failure,    // 失败Success,    //成功}//节点基类public abstract class Node{protected Node parent;protected Status status;Status Status{get{return status;}set{status = value;}}public Node(){}//声明节点状态返回方法public abstract Status Evaluate(Transform transform,Blackboard blackboard);}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using BehaviourTree;namespace BehaviourTree
{//复合节点类public abstract class Composite : Node{//子节点列表protected List<Node> children = new List<Node>();protected int index;//子节点下标计数protected Composite(List<Node> children){index = 0;foreach(var child in children) {this.children.Add(child);}}}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using BehaviourTree;namespace BehaviourTree
{//修饰器节点public abstract class Decorator : Node{//子节点列表protected List<Node> children;protected Decorator(List<Node> children){children = new List<Node>(){};foreach(var child in children) {this.children.Add(child);}}}}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using BehaviourTree;namespace BehaviourTree
{//选择节点,所有子节点都为失败则失败public class Selector : Composite{public Selector(List<Node> children) : base(children){}//所有子节点都为失败则失败public override Status Evaluate(Transform transform, Blackboard blackboard){if(index>=children.Count){index = 0;return Status.Success;}var status = children[index].Evaluate(transform,blackboard);switch(status){case Status.Success:index = 0;return Status.Success;case Status.Failure:index+=1;if(index>=children.Count){index = 0;return Status.Failure;}return Status.Running;case Status.Running:return Status.Running;default:return Status.Failure;}}}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using BehaviourTree;namespace BehaviourTree
{//顺序节点,所有子节点成功才成功public class Sequencer : Composite{public Sequencer(List<Node> children) : base(children){}//所有子节点成功才成功public override Status Evaluate(Transform transform, Blackboard blackboard){if(index>=children.Count){index = 0;return Status.Success;}var status = children[index].Evaluate(transform,blackboard);switch(status){case Status.Success:index+=1;if(index>=children.Count){index = 0;return Status.Success;}return Status.Running;case Status.Failure:return Status.Failure;case Status.Running:return Status.Running;default:return Status.Failure;}}}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using BehaviourTree;namespace BehaviourTree
{//任务节点,这里会处理对象具体行为逻辑(叶节点)public abstract class Task : Node{}
}

简单使用
实现敌人在两点之间巡逻,人物靠近会变红温并停止移动,人物远离时继续巡逻
在这里插入图片描述

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using BehaviourTree;
using System.ComponentModel.Design.Serialization;
using System.Linq;namespace BehaviourTree
{public class EnemyBT : BehaviourTree{Vector3 aPos = new Vector3(4.07999992f,-2.21000004f,-2);Vector3 bPos = new Vector3(4.07999992f,1.65999997f,-2)protected override void Init(){//调用基类初始化base.Init();//创建变红节点TurnRed turnRed = new TurnRed();//创建巡逻节点Patrol patrol = new Patrol(aPos,bPos);//创建查找节点FindObject findObject = new FindObject();//创建侦查节点子节点序列Node[] spyChildren = {findObject,turnRed};//创建顺序节点用于执行侦查行为EnemySequencer enemySequencer = new EnemySequencer(spyChildren.ToList());//创建根节点子节点序列Node[] selectorChildren = {enemySequencer,patrol};//创建选择节点用于处理侦查和巡逻行为EnemySelector enemySelector = new EnemySelector(selectorChildren.ToList());//将选择节点设置为根节点Root = enemySelector;}}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using BehaviourTree;namespace BehaviourTree
{public class EnemySelector : Selector{public EnemySelector(List<Node> children) : base(children){}}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using BehaviourTree;namespace BehaviourTree
{public class EnemySequencer : Sequencer{public EnemySequencer(List<Node> children) : base(children){}}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using BehaviourTree;
using DG.Tweening;namespace BehaviourTree
{public class FindObject : Task{float radius = 5f;int layer = 512;public override Status Evaluate(Transform transform, Blackboard blackboard){Collider2D obj = Physics2D.OverlapCircle(transform.position,radius,layer);if(obj!=null){return Status.Success;   }transform.gameObject.GetComponent<SpriteRenderer>().DOColor(Color.white,1);return Status.Failure;}}
}

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using BehaviourTree;
using DG.Tweening;namespace BehaviourTree
{//在aPoint和bPoint之间来回移动public class Patrol : Task{Vector3 aPoint;Vector3 bPoint;float speed = 4f;Vector3 target;public Patrol(Vector3 aPos,Vector3 bPos){aPoint = aPos;bPoint = bPos;target = aPoint;}public override Status Evaluate(Transform transform, Blackboard blackboard){if(Vector2.Distance(transform.position,target)<0.1f){if(target == aPoint){target = bPoint;}else{target = aPoint;}}else{transform.position = Vector2.MoveTowards(transform.position,target,Time.deltaTime*speed);}return Status.Success;}}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using BehaviourTree;
using DG.Tweening;namespace BehaviourTree
{//变红public class TurnRed : Task{Vector3 bPoint;public override Status Evaluate(Transform transform, Blackboard blackboard){transform.gameObject.GetComponent<SpriteRenderer>().DOColor(Color.red,1);return Status.Success;}}
}

相关文章:

行为树(Behavior Trees)

行为树&#xff08;Behavior Trees&#xff09;是一种在游戏开发中广泛使用的AI设计模式&#xff0c;主要用于描述AI的行为和决策过程&#xff0c;实现更加智能和自然的游戏AI。它由多个节点组成&#xff0c;每个节点代表一个行为或决策&#xff0c;按照特定的方式连接在一起&a…...

opensssl BIO方式https客户端

废话不多说&#xff0c;代码中使用了两种https客户端的实现方式。 #include <windows.h> #include <WinSock.h>#pragma comment(lib,"ws2_32.lib") #include "../include/openssl\ssl.h" #include "../include/openssl\err.h"#pragm…...

JavaScript之判断是否整数、取余、取整、进制、位或、ES6

MENU 方法一方式二方式三方式四方式五结束语 方法一 使用取余运算符判断&#xff0c;利用任何整数都会被1整除的原理&#xff0c;即余数是0的特点&#xff0c;通过这个规则来判断是否是整数。 let isInteger (val) > val % 1 0;// true isInteger(5); // false isInteger(…...

【打造你自己的Shell:编写定制化命令行体验】

本节重点&#xff1a; 学习进程创建,fork/vfork 学习到进程等待 学习到进程程序替换, 微型shell&#xff0c;重新认识shell运行原理 学习到进程终止,认识$? 一、进程创建 1.1.fork函数初识 在linux中fork函数时非常重要的函数&#xff0c;它从已存在进程中创建一个新进程…...

PGSQL主键序列

PostgreSQL和 MySQL数据库还是有一定的区别。 下面了解一下 PGSQL的主键序列。 一、主键 1、系统自带主键序列 在 PostgreSQL 中&#xff0c;GENERATED BY DEFAULT 和 GENERATED ALWAYS 是用于定义自动生成的列&#xff08;Generated Column&#xff09;的选项。一般可作用…...

pg14.2迁移至KingbaseV8R6后部分表记录数为空

pg14.2迁移至KingbaseV8R6后部分表记录数为空 问题描述 kdts工具迁移详情里显示表数据已迁移成功&#xff0c;但是迁移后测试发现部份表记录数为空 分别查看源库和目标库表记录数 --源库 select count(*) from aaf_sys_param order by 1; 229条--目录库 select count(*) fr…...

【Spring 篇】深入解析SpringMVC的组件魅力

SpringMVC&#xff0c;这个名字在Java Web开发者的耳边仿佛是一首动听的旋律&#xff0c;携着轻盈的氛围&#xff0c;带给我们一种愉悦的编程体验。但是&#xff0c;当我们深入探寻这个框架时&#xff0c;它的魅力远不止表面的简单&#xff0c;它由许多组件构成&#xff0c;每个…...

HPsocket 在 C# 中的运用:一款优秀的 socket 通信框架

摘要&#xff1a;本文将为您详细介绍 HPsocket&#xff0c;一款适用于 win32 平台的 socket 通信框架。同时&#xff0c;我们还将探讨如何在 C# 项目中使用 HPsocket&#xff0c;实现网络通信功能。通过本文&#xff0c;您将深入了解 HPsocket 的特点、优势以及在 C# 中的实际应…...

黑豹程序员-MyBatisPlus封装SQL的where条件的对象 QueryWrapper

说明 我们使用MybatisPlus时&#xff0c;我们可以不直接通过SQL操作数据库&#xff0c;而使用面向对象的方式。 其中遇到一个问题&#xff0c;就是如何用面向对象的方式实现 SQL中的where条件拼接。 MybatisPlus很体贴&#xff0c;它提供了一个QueryWrapper&#xff0c;查询包…...

每日一题——LeetCode1252.奇数值单元格的数目

进阶&#xff1a;你可以设计一个时间复杂度为 O(n m indices.length) 且仅用 O(n m) 额外空间的算法来解决此问题吗&#xff1f; 方法一 直接模拟&#xff1a; 创建一个n x m的矩阵&#xff0c;初始化所有元素为0&#xff0c;对于indices中的每一对[ri,ci]&#xff0c;将矩…...

C#学习笔记3-函数与单元测试

现在开始参考书籍变为&#xff1a;《C# 12 and .NET 8 – Modern Cross-Platform Development.Mark Price》 函数 Writing, Debugging, and Testing Functions 写函数Debug运行时 logging单元测试 写函数 一个有着 XML 注释的函数 这里直接举一个例子&#xff1a; Numbe…...

osg屏幕事件处理器和状态集操控器学习

1 osgViewer::WindowSizeHandler 该事件处理器提供了对窗体屏幕的控制,功能如下: 按住或再次键盘f键,则三维窗体在全屏和退出全屏之间切换; 按住键盘>键,则屏幕分辨率增加; 按住键盘<键,则屏幕分辨率减小; 2 osgGA::StateSetManipulator 该事件处理器是状态集操…...

中国泛娱乐出海视频字幕解决方案

随着企业泛娱乐出海越来越成为热门&#xff0c;自动加载视频字幕需求变得越来越普遍&#xff0c;这能够为用户观众提供更好的视频体验。此次九河云为客户带来了aws视频字幕解决方案&#xff0c;满足客户视频字幕生成、翻译及后续编辑等完整工作流的需求。 客户价值&#xff1a…...

iOS原生应用屏幕适配完整流程

1. 已iPhone 11 布局为设计布局,其他机型已这个来适配 2.变量与控件对应关系 txtViewer: txtAccount txtpwd seg btnOk 3.适配方法实现: //iOS屏幕适配 -(vo...

【征服redis8】Redis的AOF持久化

Redis 支持多种持久化方式来保证数据的可靠性和持久性。前面我们介绍了RDB方式。我们我们介绍第二种方式——AOF&#xff08;Append Only File&#xff09;机制是一种常用的持久化方式&#xff0c;它记录了所有对 Redis 数据库进行修改的命令&#xff0c;在 Redis 重启时可以使…...

【动态规划】【二分查找】【C++算法】730. 统计不同回文子序列

作者推荐 【动态规划】【数学】【C算法】18赛车 涉及知识点 动态规划 二分查找 LeetCode730. 统计不同回文子序列 给你一个字符串 s &#xff0c;返回 s 中不同的非空回文子序列个数 。由于答案可能很大&#xff0c;请返回对 109 7 取余 的结果。 字符串的子序列可以经由…...

android 和 opencv 开发环境搭建

本文详细说明给android项目添加opencv库的详细步骤&#xff0c;并通过实现图片灰度化来查看配置是否成功。 下载OPENCV ANDROID SDK 到官网下载 打开 https://opencv.org/releases/ 选择android&#xff0c;下载完成后解压出下面的文件&#xff1a; 安装android sdk 和 ndk …...

elasticsearch[一]-索引库操作(轻松创建)、文档增删改查、批量写入(效率倍增)

elasticsearch[一]-索引库操作(轻松创建)、文档增删改查、批量写入(效率倍增) 1、初始化 RestClient 在 elasticsearch 提供的 API 中&#xff0c;与 elasticsearch 一切交互都封装在一个名为 RestHighLevelClient 的类中&#xff0c;必须先完成这个对象的初始化&#xff0c;…...

tp6框架中Http类 请求的header、body参数传参 及post、file格式

引入Http类&#xff1a; 在需要使用的地方引入Http类&#xff1a; use think\facade\Http; GET请求示例&#xff1a;$response Http::get(https://example.com/api/resource); 设置Header参数&#xff1a; $headers [ Authorization > Bearer YourAccessToken, Conte…...

基于极限学习机的图像处理,基于ELM的图像分割,基于极限学习机的细胞分割

目录 背影 极限学习机 基于极限学习机的图像,基于ELM的图像分割 主要参数 MATLAB代码 效果图 结果分析 展望 完整代码下载链接:基于极限学习机的图像,基于ELM的图像分割(代码完整,数据齐全)资源-CSDN文库 https://download.csdn.net/download/abc991835105/88759192 背…...

Linux链表操作全解析

Linux C语言链表深度解析与实战技巧 一、链表基础概念与内核链表优势1.1 为什么使用链表&#xff1f;1.2 Linux 内核链表与用户态链表的区别 二、内核链表结构与宏解析常用宏/函数 三、内核链表的优点四、用户态链表示例五、双向循环链表在内核中的实现优势5.1 插入效率5.2 安全…...

基于距离变化能量开销动态调整的WSN低功耗拓扑控制开销算法matlab仿真

目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.算法仿真参数 5.算法理论概述 6.参考文献 7.完整程序 1.程序功能描述 通过动态调整节点通信的能量开销&#xff0c;平衡网络负载&#xff0c;延长WSN生命周期。具体通过建立基于距离的能量消耗模型&am…...

DockerHub与私有镜像仓库在容器化中的应用与管理

哈喽&#xff0c;大家好&#xff0c;我是左手python&#xff01; Docker Hub的应用与管理 Docker Hub的基本概念与使用方法 Docker Hub是Docker官方提供的一个公共镜像仓库&#xff0c;用户可以在其中找到各种操作系统、软件和应用的镜像。开发者可以通过Docker Hub轻松获取所…...

深入解析C++中的extern关键字:跨文件共享变量与函数的终极指南

&#x1f680; C extern 关键字深度解析&#xff1a;跨文件编程的终极指南 &#x1f4c5; 更新时间&#xff1a;2025年6月5日 &#x1f3f7;️ 标签&#xff1a;C | extern关键字 | 多文件编程 | 链接与声明 | 现代C 文章目录 前言&#x1f525;一、extern 是什么&#xff1f;&…...

实现弹窗随键盘上移居中

实现弹窗随键盘上移的核心思路 在Android中&#xff0c;可以通过监听键盘的显示和隐藏事件&#xff0c;动态调整弹窗的位置。关键点在于获取键盘高度&#xff0c;并计算剩余屏幕空间以重新定位弹窗。 // 在Activity或Fragment中设置键盘监听 val rootView findViewById<V…...

图表类系列各种样式PPT模版分享

图标图表系列PPT模版&#xff0c;柱状图PPT模版&#xff0c;线状图PPT模版&#xff0c;折线图PPT模版&#xff0c;饼状图PPT模版&#xff0c;雷达图PPT模版&#xff0c;树状图PPT模版 图表类系列各种样式PPT模版分享&#xff1a;图表系列PPT模板https://pan.quark.cn/s/20d40aa…...

Java求职者面试指南:Spring、Spring Boot、MyBatis框架与计算机基础问题解析

Java求职者面试指南&#xff1a;Spring、Spring Boot、MyBatis框架与计算机基础问题解析 一、第一轮提问&#xff08;基础概念问题&#xff09; 1. 请解释Spring框架的核心容器是什么&#xff1f;它在Spring中起到什么作用&#xff1f; Spring框架的核心容器是IoC容器&#…...

springboot整合VUE之在线教育管理系统简介

可以学习到的技能 学会常用技术栈的使用 独立开发项目 学会前端的开发流程 学会后端的开发流程 学会数据库的设计 学会前后端接口调用方式 学会多模块之间的关联 学会数据的处理 适用人群 在校学生&#xff0c;小白用户&#xff0c;想学习知识的 有点基础&#xff0c;想要通过项…...

人工智能(大型语言模型 LLMs)对不同学科的影响以及由此产生的新学习方式

今天是关于AI如何在教学中增强学生的学习体验&#xff0c;我把重要信息标红了。人文学科的价值被低估了 ⬇️ 转型与必要性 人工智能正在深刻地改变教育&#xff0c;这并非炒作&#xff0c;而是已经发生的巨大变革。教育机构和教育者不能忽视它&#xff0c;试图简单地禁止学生使…...

LLMs 系列实操科普(1)

写在前面&#xff1a; 本期内容我们继续 Andrej Karpathy 的《How I use LLMs》讲座内容&#xff0c;原视频时长 ~130 分钟&#xff0c;以实操演示主流的一些 LLMs 的使用&#xff0c;由于涉及到实操&#xff0c;实际上并不适合以文字整理&#xff0c;但还是决定尽量整理一份笔…...