用行为树的方式思考问题

这段时间做了很多和AI无关的事情,做了个Flash的3D引擎,用汇编写了些shader,做了很多引擎的工具,脚本,插件,游戏也发布了首个预告片,一年多的工作收获满满,职位从AI Engineer变成了Engineer(“专科大夫”到“全科大夫”?)。虽然很多工作看似和AI没什么关系,但做AI时的那些经验也带给了我不少思考和借鉴。我的博客里分享的最多的就是行为树(Behavior Tree),被浏览的最多的是行为树,提问最多的还是行为树,行为树作为现在AI的流行技术确实得到了很多的关注,不少游戏和开发者都从中受益。我今天想聊聊的并不是行为树在AI中的某个具体应用,就像标题所说的,我想聊聊如何用行为树的方式去思考问题,这也是我这些时间做其他东西的时候一直在考虑的,并且我也成功的将行为树的思想用到了非AI的模块中,效果不错。

  行为树从本质上来说,是一颗逻辑树,它把所有的行为逻辑用树形结构串联起来,仔细观察的话,可以发现行为树的核心思想有三个方面:

  • 逻辑分离
  • 逻辑关联
  • 逻辑抽象

  听上去很玄乎,其实是很简单的东西,可以先想想我们平时要做一个功能是怎么做的,我们会先定义一个函数,定义好输入和输出,然后在这个函数里写代码来实现功能逻辑,这是第一步,是最直接和简单的方式。后来,当这个功能越来越复杂的时候,这个函数里的代码就会越来越长,变得难以阅读和维护,我们就会把一些逻辑拿出去,变成另一个函数,原先那个函数里就变成了一些简单逻辑和函数的组合,再然后,我们发现有些函数可以变成一些通用函数,我们就会把这些函数集合起来变成一个库,这样其他的函数也可以访问这个函数来获取他的逻辑功能。

  这里的整个过程就包含了上面所说的三个方面,把逻辑移出去变成一个新的函数,就是“逻辑分离”,原本函数里的简单逻辑和函数组合就是“逻辑关联”,把函数变成通用库就是“逻辑抽象”。AI是游戏的逻辑大户,充斥着大量的游戏逻辑和算法,所以就特别需要好的架构来维护和管理“逻辑”,要不整个代码就是一团糟,不仅无法维护,而且也很难除错,现有的AI的架构基本都围绕这个展开。

  让我用有限状态机(FSM)来举个例子,在FSM中就包含了逻辑的分离和抽象,它有“状态”这个概念,这就是一个逻辑块,它的逻辑块也可以重用,但它对于逻辑的关联做的相对比较薄弱,由状态自己来决定何时跳转,并且跳转比较随意,所以逻辑的关联性比较模糊,这就导致FSM在多状态的情况下很难维护。所以后来有了层次化的有限状态机(HFSM),部分解决了逻辑关联模糊的问题,但FSM的设计原理导致它并没有办法从根本上解决问题。但对于状态和跳转都不是很复杂的功能,FSM是个不错的选择。

  让我们再回到行为树,行为树把逻辑分散在节点中,每个节点负责自己的逻辑部分,这些逻辑节点又可以被放在行为树的其他部分,也就是可以被重用。在这个基础上,行为树又抽象了三个逻辑概念,控制逻辑,前提逻辑,行为逻辑,其中行为逻辑用来描述功能,控制逻辑和前提逻辑用来描述逻辑间的关联,对于逻辑关联的抽象是行为树相较于FSM的一个重大突破,它使得逻辑的关联“可视化”了,用过行为树的人都会有这样的感觉,我只要看一下树的结构,我就能知道整个AI行为是如何协作的了,也正是这样的优势使得行为树现在被越来越多的用在了AI逻辑中。

  但如果我们再往前思考一步,可以发现如果仅仅把行为树限制在AI部分,显得有点可惜,就像我前面一直强调,行为树就是逻辑树,是一种对于逻辑的维护和管理的架构。游戏中很多地方都是有逻辑的,有些甚至会非常复杂,这些地方为什么不能用行为树的方式来思考和实现呢?经过实践,我发现这是完完全全可行的,我甚至可以这样说,只要存在复杂的逻辑,就可以用行为树的方式去做,它可以很好的帮助你理清思路,实现漂亮的逻辑代码。由于行为树与AI有了“密切”的绑定,所以甚少接触AI的程序员对行为树基本不是很了解,这也导致行为树并没有得到广泛的应用,甚至都没有作为一个候选方案。

  我有幸在现在项目里,做了很多其他的模块,所以我也把行为树的一些思路用到了其他的模块中,发现写起来非常的顺,也很爽快。我举一个我们在项目中碰到的例子,就是任务系统,做过游戏的人都知道,这个系统在逻辑层面是很复杂的,内容繁多,但如果用行为树的方式去思考的话,就会发现这个复杂的问题一下子就简化了。

  仔细分析任务系统的话,可以把任务系统分成几个部分,一个是接这个任务条件,然后是任务的完成目标,然后是奖励(这个和下面的讨论关系不大,暂且略过)。我们先可以抽象两个概念,“单个条件”和“单个目标”。单个的条件包含“怎么算是达到条件”的一段逻辑,单个的目标也是一段逻辑,包含了“怎么算是完成”。所以这些都可以做成一个个逻辑单元,就像行为树的前提和行为节点一样。另外根据设计的需求,接任务的条件可能有多个,完成的目标也可以有多个,所以这些单个逻辑之间就存在逻辑关联,所以我们可以借鉴行为树中控制节点的概念,把这些逻辑关联也抽象出来,成为“关联”,比如一个最简单的逻辑关联就是“并且”,这样我们就可以描述这样一个逻辑,要完成目标1,“并且”完成目标2,这里我们就把两个“单个目标逻辑”用“关联”串起来了。

  最后,我们就在每个任务中定义了两颗逻辑树(换个通用的名称,其本质和行为树是一样的),一个是接这个任务的条件树,一个是完成这个任务的目标树,这样每个任务都可以用配置文件来配,我们也做了一个工具来帮助设计师来生成和编辑任务,作为程序只要维护那些可以被用到的“条件”,“目标”,“关联”就可以了。

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

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

相关文章

Linux常用指令2

linux的命令操作 1、日常操作命令 **查看当前所在的工作目录 pwd **查看当前系统的时间 date **查看有谁在线(哪些人登陆到了服务器) who 查看当前在线 last 查看最近的登陆历史记录 2、文件系统操作 ** ls / 查看根目录下的子节点&#xff…

qt, connect参数,Qt::DirectConnection,Qt::QueuedConnection

connect用于连接qt的信号和槽,在qt编程过程中不可或缺。它其实有第五个参数,只是一般使用默认值,在满足某些特殊需求的时候可能需要手动设置。 Qt::AutoConnection: 默认值,使用这个值则连接类型会在信号发送时决定。如…

Hbase Compaction 队列数量较大分析

目录 问题 问题原因分析 总结建议 问题 前几天朋友公司Hbase集群出现Compaction队列持续处于比较大的情况,并且mem flush队列也比较大,一起看了下问题,大概情况如下图 从图中可以看出来压缩队列总和持续在1000-2000,平对压缩队列…

java中Date和DateFormat、SimpleDateFormat类

package com.test;import java.text.DateFormat; import java.util.Date; import java.util.Random; import java.util.UUID; import java.util.concurrent.ThreadLocalRandom;public class M1001{public static void main(String[] args) {//Date表示特定的瞬间,精确到毫秒Dat…

Hbase 2.x Region in transition (永久RIT) 异常解决

环境 Hbase 版本:2.0 问题原因 hbase长时间出现RIT,并且发生RIT的Region是已经删除了的Hbase表,表未删除的情况下执行assgin可以消除该问题 Hbase Region in transition (RIT) 异常解决:https://datamining.blog.csdn.net/artic…

sigslot库源码分析

言归正传,sigslot是一个用标准C语法实现的信号与槽机制的函数库,类型和线程安全。提到信号与槽机制,恐怕最容易想到的就是大名鼎鼎的Qt所支持的对象之间通信的模式吧。不过这里的信号与槽虽然在概念上等价与Qt所实现的信号与槽,但…

Mysql for linux 安装

Mysql for linux 安装: 第一步,参考这个链接至第四步为止 https://jingyan.baidu.com/article/cd4c2979209c32756e6e60e1.html 第二步:使用rpm -qa | grep mysql 查询安装状态 第三步:使用/etc/rc.d/init.d/mysqld status 检…

Hue开发指南 - 提交 Spark 程序

目录 Hue开发指南 1.Spark文件打包成一个Jar包提交Hue运行 1.1 上传Spark Jar包至HDFS文件系统 1.2.Hue中创建Spark任务 2.多jar包导入执行(依赖jar包与主程序jar包分开打包) 2.1 修改worksapce 2.2 添加程序依赖jar包 Hue开发指南 Hue是面向 Had…

如何缩小码农和高手的差距

为什么同样的时间有的人可以漂亮的完成工作,而有些人废了很大的力气也没有完成?前者我们常常称之为“大牛”,后者我们常常叫他们“菜鸟”。当然“大牛”都是相对而言的,“大牛”也不可能方方面面都非常厉害,换句话说大…

OpenResty 安装,收集日志保存到文本文件

目录 安装 1.安装相关类库 2.安装编译openresty 3.编写配置启动openresty服务 4.通过 openresty 保存日志数据到系统 安装 1.安装相关类库 yum install -y readline-devel pcre-devel openssl-devel gcc 2.安装编译openresty wget https://openresty.org/download/open…

暗时间-领悟

作者:排长链接:https://www.zhihu.com/question/20689852/answer/23227406来源:知乎著作权归作者所有,转载请联系作者获得授权。第一次看到“暗时间”这个词,我的第一反应是有点不屑,又是一个概念噱头吧。直…

Openresty Nginx 负载均衡

目录 OpenResty Openresty 服务配置文件 启动Openresty服务 测试调用接口 Nginx 负载均衡服务 nginx 配置文件 启动服务 实现功能 测试结果 这里实现个简单的负载均衡,只做功能展示(实际业务比这复杂高,单台服务器无法满足需求的情况…

总结--美丽的敷衍

我看新年 转眼间,2015已经悄然离去,正像2015年刚来时候感叹2014的白驹过隙。年年岁岁花相似,岁岁年年人不同。时间过去了,自己又有如何的不同呢?客观的说,这一年有了一定的长进,但总感觉失去/错…

Hadoop Yarn REST API未授权漏洞利用挖矿分析

目录 一、背景情况 二、 漏洞说明 攻击步骤: 三、入侵分析 四、安全建议 清理病毒 安全加固 五、IOCs 一、背景情况 5月5日腾讯云安全曾针对攻击者利用Hadoop Yarn资源管理系统REST API未授权漏洞对服务器进行攻击,攻击者可以在未授权的情况…

读书-悟

作者:梅芳growing链接:https://www.zhihu.com/question/20689852/answer/95018631来源:知乎著作权归作者所有,转载请联系作者获得授权。《暗时间》这本书,我读过3遍,第一便是在大三时,第二遍是用…

Linux shell编程学习总结

主要内容&#xff1a; shell编程sed命令awk命令crontab定时器 什么是Shell&#xff1f; Shell是用户与内核进行交互操作的一种接口&#xff0c;目前最流行的Shell称为bash Shell Shell也是一门编程语言<解释型的编程语言>&#xff0c;即shell脚本 一个系统可以存在多…

Flink ProcessFunction 介绍使用

目录 实现功能 代码 测试 问题 官网描述&#xff1a;https://ci.apache.org/projects/flink/flink-docs-release-1.10/zh/dev/stream/operators/process_function.html The ProcessFunction is a low-level stream processing operation, giving access to the basic build…

Flink keyby 数据倾斜问题处理

上一篇我们使用keyby后发现数据严重倾斜 https://datamining.blog.csdn.net/article/details/105316728 大概看下问题所在&#xff0c;大量数据在一个subtask中运行 这里我们使用两阶段keyby 解决该问题 之前的问题如下图所示 我们期望的是 但我们的需要根据key进行聚合统计&a…

java中正则表达式

package com.test;import java.util.Scanner;public class M1001{public static void main(String[] args) {String input null;Scanner sc new Scanner(System.in);while(sc.hasNext()){inputsc.nextLine();String regex "^1[3|4|5|7|8][0-9]{9}$";//为表达式模板…