行为树行为树行为树

news2024/7/6 20:02:34

行为树由一个个节点组成

  • 结构:树状结构
  • 运行流程:从根节点开始自顶向下往下遍历,每经过一个节点就执行节点对应的功能。

我们规定,每个节点都提供自己的excute函数,返还执行失败/成功结果。
然后根据不同节点的执行结果,遍历的路径随之改变,而这个过程中遍历到什么节点就执行excute函数。

主流的行为树实现,将节点主要分为四种类型。
下面列举四种节点类型及其对应excute函数的行为:

  • 控制节点(非叶节点),用于控制如何执行子节点(控制遍历路径的走向)。
  • 条件节点(叶节点),行为是提供条件的判断结果。
  • 行为节点(叶节点):

    行为节点是代表智能体行为的叶节点,其执行函数一般位该节点代表的行为。

    行为节点的类型是比较多的,毕竟一个智能体的行为是多种多样的,而且都得根据自己的智能体模型定制行为节点类型。
    这里列举一些行为:站立,射击,移动,跟随,远离,保持距离....

  • 装饰节点 :行为是修饰(辅助)其他三类节点。例如执行结果取反/并/或,重复执行若干次等辅助修饰节点的作用,均可做成装饰节点。

持续行为

一些行为是可以瞬间执行完的(例如转身?),
而另外一些动作则是执行持续一段时间才能完成的(例如攻击从启动攻击行为到攻击结算要1秒左右的时间)。

因此,这些持续行为节点的excute函数里,应先启动智能体的持续行为,然后挂起该行为树(更通俗地说是暂停行为树),等到持续时间结束才允许退出excute函数并继续遍历该行为树。
为了支持挂起行为树而不影响其他CPU代码执行,我们往往需要利用协程等待该其行为完成而不产生CPU阻塞,而且开销远低于真正的线程。
此外,一般是一个行为树对应维护一个协程。

条件节点:

执行节点不会总是一帆风顺的,有成功也总会有失败的结果。
这就是引入前提条件的作用——
满足前提条件,才能成功执行行为,返还执行成功结果。否则不能执行行为,返还执行失败结果。

但是每个节点的前提总会不同,或有些没有前提(换句话说总是能满足前提)。

一个可行的做法是:让行为节点含有bool函数对象(或函数接口)。这样对于不同的逻辑条件,就可以写成不同的bool函数,绑定给相应的行为节点。

现在比较成熟的做法是把前提条件抽象分离成新的节点类型,称之为条件节点
将其作为叶节点混入行为树,提供条件的判断结果,交给控制节点决策。

它相当模块化,更加方便适用。

这里的Sequence节点是上面控制节点的一种:能够让其所有子节点依次运行,若运行到其中一个子节点失败则不继续往下运行。
这样可以实现出不满足条件则失败的效果。

相比较传统的有限状态机:

  • 易脚本化/可视化的决策逻辑
  • 逻辑和实现的低耦合,可复用的节点
  • 可以迅速而便捷的组织较复杂的行为决策

这里并不是说有限状态机一无所用:

  • 状态机可以搭配行为树:状态机负责智能体的身体状态,行为树则负责智能体的智能决策。这样在行为树做决策前,得考虑状态机的状态。
  • 状态机适用于简单的AI:对于区区需两三个状态的智能,状态机解决绰绰有余。
  • 状态机运行效率略高于行为树:因为状态机的运行总是在当前状态开始,而行为树的运行总在根开始,这样就额外多了一些要遍历的节点(也就多了一些运行开销)。

在《杀手:赦免》的人群系统里,人群的状态机AI只有简单的3种状态,由于人群的智能体数量较多,若采取行为树AI,则会大大影响性能。

代码示例:

enum Status {
    SUCCESS,
    FAILURE,
    RUNNING
}

// 基础节点类
abstract class Node {
    abstract execute(): Status;
}

// 非叶节点类,用于容纳子节点
abstract class CompositeNode extends Node {
    protected children: Node[] = [];

    addChild(child: Node): void {
        this.children.push(child);
    }
}

// 选择器节点:依次执行子节点,直到其中一个成功为止
class SelectorNode extends CompositeNode {
    execute(): Status {
        for (const child of this.children) {
            const status = child.execute();
            if (status === Status.SUCCESS) {
                return Status.SUCCESS;
            }
        }
        return Status.FAILURE;
    }
}

// 序列节点:依次执行子节点,直到其中一个失败为止
class SequenceNode extends CompositeNode {
    execute(): Status {
        for (const child of this.children) {
            const status = child.execute();
            if (status === Status.FAILURE) {
                return Status.FAILURE;
            }
        }
        return Status.SUCCESS;
    }
}

// 条件节点:判断某个条件是否满足,并返回结果
abstract class ConditionNode extends Node {
    abstract check(): boolean;

    execute(): Status {
        return this.check() ? Status.SUCCESS : Status.FAILURE;
    }
}

// 行为节点:执行具体的动作,并返回结果
abstract class ActionNode extends Node {
    abstract performAction(): boolean;

    execute(): Status {
        return this.performAction() ? Status.SUCCESS : Status.FAILURE;
    }
}

// 装饰节点:用于修改其他节点的行为,通常只有一个子节点
abstract class DecoratorNode extends Node {
    protected child: Node;

    constructor(child: Node) {
        super();
        this.child = child;
    }
}

// 反转节点:将子节点的结果反转
class InverterNode extends DecoratorNode {
    execute(): Status {
        const status = this.child.execute();
        if (status === Status.SUCCESS) {
            return Status.FAILURE;
        } else if (status === Status.FAILURE) {
            return Status.SUCCESS;
        } else {
            return status;
        }
    }
}

// 重复执行装饰节点:重复执行子节点指定的次数,或直到满足某个条件
class RepeaterNode extends DecoratorNode {
    private maxRepeats: number;
    private stopOnSuccess: boolean;
    private stopOnFailure: boolean;

    constructor(child: Node, maxRepeats: number, stopOnSuccess: boolean = false, stopOnFailure: boolean = false) {
        super(child);
        this.maxRepeats = maxRepeats;
        this.stopOnSuccess = stopOnSuccess;
        this.stopOnFailure = stopOnFailure;
    }

    execute(): Status {
        let count = 0;
        while (this.maxRepeats === -1 || count < this.maxRepeats) {
            const status = this.child.execute();
            if (this.stopOnSuccess && status === Status.SUCCESS) {
                return Status.SUCCESS;
            }
            if (this.stopOnFailure && status === Status.FAILURE) {
                return Status.FAILURE;
            }
            count++;
        }
        return Status.SUCCESS;
    }
}

// 判断敌人是否在范围内的条件节点
class IsEnemyInRange extends ConditionNode {
    check(): boolean {
        // 判断敌人是否在范围内
        return Math.random() < 0.5; // 50% 概率敌人在范围内
    }
}

// 追击敌人的行为节点
class ChaseEnemy extends ActionNode {
    performAction(): boolean {
        console.log("Chasing the enemy!");
        return true; // 假设追击成功
    }
}

// 攻击敌人的行为节点
class AttackEnemy extends ActionNode {
    performAction(): boolean {
        console.log("Attacking the enemy!");
        return true; // 假设攻击成功
    }
}

// 创建行为树
const root = new SelectorNode();

const sequence = new SequenceNode();
root.addChild(sequence);

const condition = new IsEnemyInRange();
sequence.addChild(condition);

const chase = new ChaseEnemy();
const repeater = new RepeaterNode(chase, 3); // 重复执行ChaseEnemy 3次
sequence.addChild(repeater);

const attack = new AttackEnemy();
sequence.addChild(attack);

// 执行行为树
const status = root.execute();
console.log(`Behavior tree execution status: ${Status[status]}`);


 

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

从0到1使用vite搭建react项目保姆级教程(持续更新中)

一、vite创建react项目 要使用Vite创建一个React项目&#xff0c;你需要按照以下步骤操作&#xff1a; 1、确保你已经安装了Node.js&#xff08;建议使用最新的稳定版本&#xff09;。 2、 使用npm命令安装Vite CLI工具&#xff0c;再来创建项目 npm create vitelatest my-vi…

【pytorch01】简单回归问题

1.梯度下降&#xff08;Gradient Descent&#xff09; y x 2 ∗ s i n ( x ) yx^{2}*sin(x) yx2∗sin(x) y ′ 2 ∗ x ∗ s i n ( x ) x 2 ∗ c o s ( x ) y2*x*sin(x) x^{2}*cos(x) y′2∗x∗sin(x)x2∗cos(x) 求最小值要求导 梯度下降定义&#xff1a;梯度下降要迭代计…

矿用行程位移传感器传感器ZE0701-06CU

矿用行程传感器概述 矿用行程传感器是一种专为煤矿等特定环境设计的传感器&#xff0c;用于监测和测量设备或部件的位移量。它们通常用于液压支架、千斤顶、掘进机等矿山设备中&#xff0c;帮助监测和控制设备的运动状态&#xff0c;以确保安全和高效的生产。 定义和功能 矿用…

异构集成封装类型2D、2.1D、2.3D、2.5D和3D封装技术

异构集成封装类型&#xff1a;2D、2.1D、2.3D、2.5D和3D封装详解 简介随着摩尔定律的放缓&#xff0c;半导体行业越来越多地采用芯片设计和异构集成封装来继续推动性能的提高。这种方法是将大型硅芯片分割成多个较小的芯片&#xff0c;分别进行设计、制造和优化&#xff0c;然后…

算法金 | 再见!!!梯度下降(多图)

大侠幸会&#xff0c;在下全网同名「算法金」 0 基础转 AI 上岸&#xff0c;多个算法赛 Top 「日更万日&#xff0c;让更多人享受智能乐趣」 接前天 李沐&#xff1a;用随机梯度下降来优化人生&#xff01; 今天把达叔 6 脉神剑给佩奇了&#xff0c;上 吴恩达&#xff1a;机器…

Python接口测试实战之搭建自动化测试框架

&#x1f345; 视频学习&#xff1a;文末有免费的配套视频可观看 &#x1f345; 点击文末小卡片&#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 一.数据分离:从Excel中读取数据 之前的用例中&#xff0c;数据直接写在代码文件里&#xff0c;不…

OpenAI新模型发布,免费开放GPT-4o!但只开放一点点...

GPT-4o 中的“o”代表“omni”——指的是 GPT-4o 的多模态。 该模型将向免费客户开放&#xff0c;这意味着任何人都可以通过 ChatGPT 访问 OpenAI 最先进的技术。 GPT-4o 是 OpenAI 昨天晚上发布的新旗舰模型&#xff0c;可以实时推理音频、视觉和文本。 据官方介绍&#xff0…

椭圆的标准方程与协方差矩阵的特征值和特征向量的关系

椭圆的标准方程与协方差矩阵的特征值和特征向量的关系 flyfish 单位圆 &#xff1a;单位圆表示在标准正交基下的分布。 椭圆 &#xff1a;通过协方差矩阵的特征向量和特征值变换得到的椭圆&#xff0c;表示数据在新的坐标系下的分布。 特征向量 &#xff1a;红色箭头表示特征…

【C语言】一维数组(详解)

目录 1. 数组的概念 2. 一维数组的创建和初始化 3. 一维数组的使用 4. 一维数组在内存中的存储 5. sizeof 计算数组元素个数 正文开始—— 1. 数组的概念 数组是一组相同类型元素的集合。 数组中存放的是1个或者多个数据&#xff0c;但是数组元素个数不能为0。…

运算放大器(运放)同相放大器电路

设计目标 输入电压ViMin输入电压ViMax输出VoMin输出VoMax电源Vcc电源Vee-1V1V-10V10V15V–15V 设计说明 这种设计将输入信号 Vi 放大&#xff0c;信号增益为 10V/V。输入信号可能来自高阻抗源&#xff08;例如 MΩ&#xff09;&#xff0c;因为该电路的输入阻抗由运算放大器…

vue3delete请求报403forbidden,前后端解决方式,cookie无效问题

在做开发时&#xff0c;前期已经在Controller类加上CrossOrigin(origins "*")&#xff0c;发送get和post请求都没问题&#xff0c;但遇到delete请求时&#xff0c;又报出跨域问题 一.前端添加proxy代理服务器&#xff08;未能解决&#xff09; 在vue.config.js中使…

PHP转Go系列 | 字符串的使用姿势

大家好&#xff0c;我是码农先森。 输出 在 PHP 语言中的输出比较简单&#xff0c;直接使用 echo 就可以。此外&#xff0c;在 PHP 中还有一个格式化输出函数 sprintf 可以用占位符替换字符串。 <?phpecho 码农先森; echo sprintf(码农:%s, 先森);在 Go 语言中调用它的输…

pikachu靶场之XSS漏洞测试

一、环境配置 1.pikachu官网下载 下载地址&#xff1a;https://github.com/zhuifengshaonianhanlu/pikachu 2.百度网盘&#xff08;里面含有pikachu跟phpstudy&#xff09; 链接&#xff1a;pikachu下载 密码&#xff1a;abcd 配置&#xff1a;pikachu下载及安装-图文详解…

14K屏FPGA通过MIPI接口点亮

一、屏参数 屏分辨率为13320*5120&#xff0c;MIPI接口8 LANE。 二、驱动接口电路 屏偏置电压5.5V&#xff0c;逻辑供电1.8V。8 LANE MIPI&#xff0c;2 PORT。 三、MIPI DSI规范 DCS (Display Command Set)&#xff1a;DCS是一个标准化的命令集&#xff0c;用于命令模式的显…

基于单片机的智能窗户控制系统的设计

摘 要&#xff1a; 根据单片机技术和现代传感器技术 &#xff0c; 本文主要针对基于单片机的智能窗户控制系统的设计进行探讨 &#xff0c; 仅供参考 。 关键词&#xff1a; 单片机 &#xff1b; 智能窗户 &#xff1b; 控制系统 &#xff1b; 设计 在现代科学技术持续发展的带…

融资融券两融利率最低多少?两融利率最低账户怎么申请?

融资融券账户余额理财技巧 融资融券账户不支持货币基金申赎、逆回购等业务&#xff0c;投资者可以将资金大于维保比例300%的部分通过银证转账转出再转入到普通账户&#xff0c;参与证券公司现金理财或逆回购等业务。 融券卖出和还券技巧 融券卖出所得的资金仅能用于买券还券&…

Linux操作系统学习:day05

内容来自&#xff1a;Linux介绍 视频推荐&#xff1a;[Linux基础入门教程-linux命令-vim-gcc/g -动态库/静态库 -makefile-gdb调试]( 目录 day0530、删除用户31、添加和删除用户组创建用户组删除用户组 32、修改密码33、使用tar工具进行压缩和解压缩压缩解压缩 34、使用zip u…

▶《强化学习的数学原理》(2024春)_西湖大学赵世钰 Ch4 值迭代 与 策略迭代 【动态规划 算法】

PPT 截取必要信息。 课程网站做习题。总体 MOOC 过一遍 1、视频 学堂在线 习题 2、过 电子书 补充 【下载&#xff1a; 本章 PDF 电子书 GitHub】 [又看了一遍视频。原来第一次跳过了好多内容。。。] 3、总体 MOOC 过一遍 习题 学堂在线 课程页面链接 中国大学MOOC 课程页面链…

【宠粉赠书】科技图表绘制:R语言数据可视化

为了回馈粉丝们的厚爱&#xff0c;今天小智给大家送上一套科研绘图的必备书籍——《R语言数据可视化&#xff1a;科技图表绘制》。下面我会详细给大家介绍这套图书&#xff0c;文末留有领取方式。 图书介绍 《R语言数据可视化&#xff1a;科技图表绘制》结合编者多年的数据分析…

jenkins安装和使用 (二)

参考视频资料 https://www.bilibili.com/video/BV1bS4y1471A?p10&vd_sourcee0dcd147bd5d730317de804d788cd6f9 安装maven插件 新建item 配置构建信息 项目地址替换为自己的实际地址 其余保持先保持默认 先然后在主页就看到了这个项目 查看控制台输出 稍等一…