当前位置: 首页 > 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】shell脚本忽略错误继续执行

在 shell 脚本中&#xff0c;可以使用 set -e 命令来设置脚本在遇到错误时退出执行。如果你希望脚本忽略错误并继续执行&#xff0c;可以在脚本开头添加 set e 命令来取消该设置。 举例1 #!/bin/bash# 取消 set -e 的设置 set e# 执行命令&#xff0c;并忽略错误 rm somefile…...

Lombok 的 @Data 注解失效,未生成 getter/setter 方法引发的HTTP 406 错误

HTTP 状态码 406 (Not Acceptable) 和 500 (Internal Server Error) 是两类完全不同的错误&#xff0c;它们的含义、原因和解决方法都有显著区别。以下是详细对比&#xff1a; 1. HTTP 406 (Not Acceptable) 含义&#xff1a; 客户端请求的内容类型与服务器支持的内容类型不匹…...

Leetcode 3577. Count the Number of Computer Unlocking Permutations

Leetcode 3577. Count the Number of Computer Unlocking Permutations 1. 解题思路2. 代码实现 题目链接&#xff1a;3577. Count the Number of Computer Unlocking Permutations 1. 解题思路 这一题其实就是一个脑筋急转弯&#xff0c;要想要能够将所有的电脑解锁&#x…...

OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别

OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别 直接训练提示词嵌入向量的核心区别 您提到的代码: prompt_embedding = initial_embedding.clone().requires_grad_(True) optimizer = torch.optim.Adam([prompt_embedding...

使用Matplotlib创建炫酷的3D散点图:数据可视化的新维度

文章目录 基础实现代码代码解析进阶技巧1. 自定义点的大小和颜色2. 添加图例和样式美化3. 真实数据应用示例实用技巧与注意事项完整示例(带样式)应用场景在数据科学和可视化领域,三维图形能为我们提供更丰富的数据洞察。本文将手把手教你如何使用Python的Matplotlib库创建引…...

佰力博科技与您探讨热释电测量的几种方法

热释电的测量主要涉及热释电系数的测定&#xff0c;这是表征热释电材料性能的重要参数。热释电系数的测量方法主要包括静态法、动态法和积分电荷法。其中&#xff0c;积分电荷法最为常用&#xff0c;其原理是通过测量在电容器上积累的热释电电荷&#xff0c;从而确定热释电系数…...

网站指纹识别

网站指纹识别 网站的最基本组成&#xff1a;服务器&#xff08;操作系统&#xff09;、中间件&#xff08;web容器&#xff09;、脚本语言、数据厍 为什么要了解这些&#xff1f;举个例子&#xff1a;发现了一个文件读取漏洞&#xff0c;我们需要读/etc/passwd&#xff0c;如…...

免费数学几何作图web平台

光锐软件免费数学工具&#xff0c;maths,数学制图&#xff0c;数学作图&#xff0c;几何作图&#xff0c;几何&#xff0c;AR开发,AR教育,增强现实,软件公司,XR,MR,VR,虚拟仿真,虚拟现实,混合现实,教育科技产品,职业模拟培训,高保真VR场景,结构互动课件,元宇宙http://xaglare.c…...

Python训练营-Day26-函数专题1:函数定义与参数

题目1&#xff1a;计算圆的面积 任务&#xff1a; 编写一个名为 calculate_circle_area 的函数&#xff0c;该函数接收圆的半径 radius 作为参数&#xff0c;并返回圆的面积。圆的面积 π * radius (可以使用 math.pi 作为 π 的值)要求&#xff1a;函数接收一个位置参数 radi…...

VSCode 使用CMake 构建 Qt 5 窗口程序

首先,目录结构如下图: 运行效果: cmake -B build cmake --build build 运行: windeployqt.exe F:\testQt5\build\Debug\app.exe main.cpp #include "mainwindow.h"#include <QAppli...