什么是GOAP(Goal-Oriented Action Planning)

介绍

在游戏中设计敌人的AI一直是很大的一块需求,在需求的最开始,我们可能就是写了一堆的if分支,然后通过一系列方法各种读取环境的信息,根据环境的信息做反应,或者是是给AI一个相对固定、循环的模式。

后来大家注意到AI的行为大量耦合在一起不便于快速开发迭代,便诞生了状态机,分割了所有的状态,后来又对状态机通过transition的状态间相互耦合感到不满意,于是诞生了复用一系列transition条件的行为树,其实也可以称为树形状态机。

但是这些AI的特点都很明显,他们都是读取环境信息,然后根据信息找到分支然后找到执行的行为,属于 应激式AI

在2003年,Jeff Orkin 发布的论文 Applying Goal-Oriented Action Planning to Games,他给我们阐述了一种基于目标的规划行为的 慎思型AI

  • 反应型AI(Reactive AI) :先接受刺激输入,然后执行对应行为
  • 慎思型AI(Deliberative AI):将环境和背景条件纳入决策考量,可以胜任复杂决策

    这个方案下的AI会制定自己的计划以满足他的目标,AI角色将会表现出较少重复的、可预测的行为,并且可以调整他的行为以适应他当前的情况。

    这个方案的好处就是令状态机的状态们完全解耦,便于设计师在面临超大复杂度AI的设计中处理太多状态间的关系问题,也可以采用一些分模块、分等级的思路来更好的管理AI。

    如果想要NPC对特定输入进行特定反应,那么可能GOAP并不适合,因为决策、规划需要时间。状态机和行为树在这点需求上比GOAP更合适,但是如果想要了各种互动和涌现式体验,那么GOAP是一个不错的选择。

细节

An agent uses a planner to formulate a sequence of actions that will satisfy some goal.

解释一下GOAP中基础的概念:

  • Goal:一个目标,一个世界状态数据,纯粹的数据,各个goal之间有优先级
  • Action:一个改变世界状态数据的行为
    • Precondition:执行这个行为的条件,也是世界状态数据
    • Effect:执行成功后对世界状态数据的影响
  • Plan:为了达到目标制定的一系列Action列表

同一时刻,只有一个目标启动,控制着玩家行为。

GOAP 中的Goal不包括Plan,也没有硬编码某个Goal的处理流程,他的Goal只是定义了数据,满足条件的过程是通过规划器实时决定的。Plan就是为了达到Goal State而规划出的Action list。

Action是一个独立的原子的Step,会让角色做某件事,去某个点、和xx交互、攻击。action有长有短,有的依赖于动画是否播完,每个action都有一定的条件和影响。

有时候我们对一扇门可以 轻轻推开、也可以用力把它砸开,我们应该有一个外部的机制决定对门行为的前置条件。

而一些Memory、Sensor,这些其实是规划器之外的都可以理解为给规划器的数据源。

因为goap把目标定义成了数学结构,是定量的表达的,然后就得到一个基于完成目标的规划问题,给所有的action都定义cost,Plan其实就是一个在图里找最短路径的问题。

原文中作者推荐了使用A* 的启发式搜索,goap中走的一个反向的规划,起点是Goal的世界状态,终点是当前状态,一定要规划到终点,以终为始的规划方法。

根据cost得到最小cost路径,但是实际上不一定是最短的方式,人定义的cost,cost最小也不一定是最快抵达的路径,cost通常会加上一些修改系数,给一些动态执行的action去有改变cost大小的能力。

难点与挑战

这part我们主要分析了gdc2015 goap十年、gdc2021 育碧goap的关键内容。顺带一提,2023年SE在GDC上也有GOAP的分享,相信很快他们的研究也会放出 。

goap十年中主要包含 《中土世界:摩多之影》、《古墓丽影》,育碧则是从奥德赛之后,大的AI架构往GOAP迁移。

世界表达

我们需要的世界状态并不是简单指的游戏的地图环境,而是指所有可用于决策规划的信息,可以理解为智能体的所能感觉到的东西。

世界表示 比如使用一个世界属性的数组,世界属性包括 键值对,键可以是枚举,这个世界属性有时候还要标记出属于哪个object。

以这种状态表示的世界是一个超大的、不切实际的任务,我们其实只需要表示可以规划的最小的世界属性集合就行了,隔离杂乱的干扰属性是规划的关键,因为状态数量越多,每个状态加入有true或者false,n个属性总共的状态数量就是2^n的寻路的节点数量。

这样如果我们要支持一个高度复杂的AI的话要定义世界的信息就非常多,所有的数据都放在一层规划就会效率很低,并且很多数据不好量化,实现上也要注意性能。

具体类型表示

举个例子,在Regoap(一个Unity GOAP) 开源库里,他的state表达就是一个字典,里面就是string to object的一个pair。这个object里面可以放vector、bool、等任意类型。可以随时往字典里插入新的state。其实他就没有控制复杂度,并且这个值类型转object有装箱开销,并且他后面直接调用的Object.Equal来判断状态是否满足,其他子类型都重写了这个Equal方法并且使用了RTTI,效率较低。

育碧在这里其实把世界状态表述的和行为树的黑板一样,在编辑器下可以配置字符串到具体类型的表,规划器可以从黑板里读取数据然后进行规划,游戏中其他的组件单位和逻辑则可能改写黑板的数据。

字符串表示

在作者2004年的文章有提到关于世界状态的内容,他觉得可以使用类似术语的方式来定义行为,说白了就是使用字符串,然后用字符串进行比对,将规划中所有会出现的内容全部定义为字符串,而很多语言其实在处理字符串的时候有编译期优化,编译期确定的相同字符串的内容会指向同一个地址,这样比对速度会快很多。其实这种模式就有点像人类的符号学,用符号指代一个东西,通过符号来判断非常快速,目前来说我比较看好这种方案。

这种方案的一个问题在于,要想比较的快速,就要依赖编译期优化,意味着所有的字符串都不好定义在代码文件外部,其实可以通过外部文件生成代码的方式来解决,最后会得到string to string的一个pair。同时这种方案对于运行时的数据(比如一个随时变化的位置点)就不是很好处理,要动态生成字符串 ,这种方案其实适合放在顶层,value比较固定的情况,做复杂AI最上层的策略判断。

bool转化为枚举

这是Middle-earth: Shadow of Mordor的一个优化方法,他们注意到有大量的bool变量,通过合并一些bool变量成枚举的方式降低状态数量级,降低了节点数量就减少了A* 寻路的负担

规划器

Regoap流程

在前面我们已经聊到过规划器,这里简单说一下Unity ReGoap的规划器和智能体执行流程,借烟雨一图。

Agent就是负责控制AI逻辑的载体,Awake时候所有的Action、Goal、Memory组件都汇总到agent身上工作。

Start开始,CalculateNewGoal会从可行的Goal列表里选一个优先级最高的出来,如果在plannnig则不选择。

Plan开始,起点是Goal的满足,终点是 当前的entity状态。根据State数据创建A* 寻路使用的节点,第一个节点是NoAction的,我们将其加入优先队列,然后进入循环,直到优先队列为空、寻路算法迭代次数过多、达到了目标节点就停止循环。

每次循环首先将优先队列里第一个节点弹出,也就是cost最低的state Node,第一次就是弹出Goal的StateNode。

然后寻找一个可能的邻居节点,这时候他遍历了所有的Action,然后检查Action是否满足:

  • 1、action有effect可以达到goal需要的State
  • 2、Action没有precondition和goal冲突,假如有precondition有冲突同时effect又可以修复冲突,那么也可以当做邻居
  • 3、没有effect和goal冲突
  • 4、程序上允许你这么干,代码运行的可行性检测

    都满足则这个Action可以作为当前State的邻居,生成邻居Node的时候同时得到邻居node的cost值。

    在节点图里搜索需要定义cost,

    cost = g + h

    g是plan到此经过的action的的cost,h是尚未满足的状态数量,可以乘一个系数,ReGoap经常会出现g很大,h较小的情况。

    如果h的系数为0,则全为g,A* 退化成dijkstra算法,如果h很大,g很小,A* 则更倾向于贪心算法。

初始化邻居Node的时候要将当前的Node的Goal State更新,因为每个邻居node其实都代表了 一路采用了什么Action才到达目前的State的过程,一个ActionEffect会满足之前的Goal的State,于是我们Effect满足的Goal State删除,然后将Action的Precondition和这个Goal State合并,就得到了新的Goal State。

把所有的邻居遍历一遍,然后,我们需要检查当前这个state在之前的迭代中是否出现过,相同的State的cost可能会存在不同,我们需要取最小cost的node,要将之前的高cost node给删掉,把这个小cost node扔进优先队列作为替代。

最后我们plan会得到一个玩家起始状态一样的Node,若没有得到,则说明规划失败了。

规划成功了就会得到一个Plan,就是Action数组,就让我们的智能体去执行这一系列Action。

在ReGoap里作者提供了许多单元测试,可以方便的测试作者的规划代码,感兴趣的读者也可以试试。

Middle-earth: Shadow of Mordor的系统分层

Middle-earth: Shadow of Mordor也谈到了有关优化器的其他优化方法,因为数据量越大节点越多规划器的负担越重。

第一个做法就是分层,分层的目的是要尽量将Plan的路径变短。

他们将很多的逻辑从Planner系统中移除,Planner不会做每件事,他只会做高层的规划,剩下的交给其他底层系统来执行负担。

比如他们做了LowLevelSystem

比如在已经在播某个动画,武器可能会自动收起来,equip unequip系统,把很多的Action简化到了LowLevelSystem里,做成自动动作。其实有点像大脑和小脑的关系。

可能攻击方案会做成一个单独的LowLevel系统、移动方案会做成一个单独LowLevelSystgem、动画选择也会做成LowLevelSystem。

他们还做了一些MiddleLevel,称为planner driving system 就是用来影响规划器的system

本来你可能有一个Goal——吃着火锅唱着歌要开开心心去上任县长了,但是突然身边有一个人被杀了,你的情绪就变得很恐惧、很紧张,然后你的Goal就变成了 活下去,开始小心翼翼探查周边的情况。

然后这些planner driving system,还可以在团队之间给各个小队成员们传递信息,像一个群体系统,同时这个系统可能包含Sensor,给Planner提供数据源。

然后是HighLevelSystem,这块个人理解较多,说的不好建议去看原视频,

以调查为例,比如一个兽人,发现队友倒了,感到不对,然后开始调查的Plan,

我们希望一个小队的兽人是各有各的反应的,但是把这些东西全部加到planner里又会增加planner的复杂度,我们的做法是让兽人把观察到的信息上报到highlevelsystem,highlevelsystem,他会有一个角色系统,plan完之后会给小队里兽人分配角色,不同角色有不同的interest,也会有不同的反应。

可能有的角色不做规划而只是跟着那几个做了规划的角色行动,这也是一个优化点,缓存复用别人规划过的流程。

古墓丽影2013的Motive系统

古墓丽影给goap system加入了一些针对gameplay需求的改变,个人理解这都是为了更加自由、方便设计而做出的改变,其实他的Planning在整体的地位就感觉明显不如前面的游戏。

一个经验:plan一个cost不高的action可能会因为各种runtime下情况而变得开销很高

比如这里range attack 11比melee attack 21要cost低,拿着范围武器的时候才可以让AI执行范围攻击。

其实他可以把这些逻辑放进Goap规划的,但是为了减少节点数量可以将这些固定的逻辑抽出来,所以有时候也会使用这种在外部的条件来影响规划器。比如这里对range attack施加硬性攻击约束就是有必要的,这时候在外部可能就会写一些hard code的逻辑可能让他在某些case下更倾向于做什么。

他们做了一套motive系统,一言以蔽之就是他们想在外部有修改动态规划流程的能力,和之前的planner driving system很像,不过他们多做到了Action的数据根据情况改变而改变。

Action的Cost可能会因为一些case而变化。

Action的Precondition也可能跟着实际的情况变化而变化,个人理解这都是方便设计而做的东西。

Action之间甚至可以有父子关系,父Action完成了子Action的cost可能会受到影响,某些action可能会触发plan system的重新plan,但其实这里已经和之前GOAP的设计思路分开了,原本的版本可能各个Action越独立越好,但有时有依赖也不错达成设计目的会方便。

古墓丽影的goap还会追踪Goal、action成功率会用来影响Plan的规划。

分享者指出了开发中两个常问的问题:

  • 当前Plan的细节

    • 到底是怎么触发的plan
    • Action什么时候执行的
    • 需要Plan的每一步的计算流程
    • 每一部分的完成情况
  • 为什么 NPC 现在不做点别的事
    • 主要讲的是NPC的闲置问题

工具

渡神纪针对GOAP开发了完善的Debug工具,分享者在这里提到了两种工具

规划管理器(Planner Monitor)

规划管理器会输出每次规划评估的所有分支的Log,包括各种最终选择执行的规划,以及其他评估的规划分支,以及更详细的各个行动条件的满足情况以及成本等。

古墓丽影也有生成的Behavior Graph,个人感觉这种可视化的图更好。

包括用于规划的可用目标(Available Goals)、可用行动(Available Actions),以及事先被过滤掉的行动(Discarded Actions),包括这些行动是哪个条件不满足才被过滤掉的。

GOAP自动化统计模块

此工具是一个执行模式,可以记录下各种条件在GOAP规划中的情况(成功、失败、被选入最终规划),辅助设计的功用,可以方便的进行剖析。

这里会记录哪些行动从来没有被选取过,从而方便开发者了解是不是某些条件过于严格,或者是行动本身不合理,或者是数据存在错误。分享者指出,最终他们会优化到没有任何一个行动是从未被选取过的。

思考

我们需要解决很多问题,包括:

1、高效的世界表达

2、分层减少规划器的负担

3、行为模块化利于维护

4、更加自由的设计方法

5、完善的Debug工具

6、解决AI反应慢的问题

7、要给智能体足够多的选择,并且每个选择有各自不同的意义

GOAP因为需要规划,所以反应相对慢,可能通过一些LowLevelSystem可以解决部分问题。

我们可以通过替换planner的方式来实现不同风格的AI,可能AI不一定能规划到终点,规划器可能不一定使用反向规划法,使用正向规划也不错,从当前状态出发,就算没有规划到目标,AI也要可能也要先动起来,可能这样会更加有复杂的人的感觉,但是这样也可能带来一些永远完不成目标的情况,关于复杂 像人 好不好,还是看需求想要什么样的。

GOAP这个结构其实可以理解为一种思想,通过指定一些规划的规则 来生成一些包含许多变化的结果,但是这个变化又具备一定的可控制性。这个结构我与人讨论,设想中感觉用来做一些基于目的的故事生成感觉也可行,相当有意思的结构。

相关资料

【GDC挖了它!】刺客信条奥德赛和渡神纪的AI行为规划

目标导向的AI系统(Goal Oriented Action Planning)技术分享

GOAP总站

ReGoap

2023.3.30

游戏AI——GOAP技术要点的更多相关文章

  1. 趣说游戏AI开发:对状态机的褒扬和批判

    0x00 前言 因为临近年关工作繁忙,已经有一段时间没有更新博客了.到了元旦终于有时间来写点东西,既是积累也是分享.如题目所示,本文要来聊一聊在游戏开发中经常会涉及到的话题--游戏AI.设计游戏AI的 ...

  2. 使用行为树(Behavior Tree)实现游戏AI

    ——————————————————————— 谈到游戏AI,很明显智能体拥有的知识条目越多,便显得更智能,但维护庞大数量的知识条目是个噩梦:使用有限状态机(FSM),分层有限状态机(HFSM),决策 ...

  3. 游戏AI之初步介绍(0)

    目录 游戏AI是什么? 游戏AI和理论AI 智能的假象 (更新)游戏AI和机器学习 介绍一些游戏AI 4X游戏AI <求生之路>系列 角色扮演/沙盒游戏中的NPC 游戏AI 需要学些什么? ...

  4. 游戏AI之路径规划(3)

    目录 使用路径点(Way Point)作为节点 洪水填充算法创建路径点 使用导航网(Navigation Mesh)作为节点 区域分割 预计算 路径查询表 路径成本查询表 寻路的改进 平均帧运算 路径 ...

  5. 游戏AI之决策结构—有限状态机/行为树(2)

    目录 有限状态机 行为树 控制节点 条件节点 行为节点 装饰节点 总结 额外/细节/优化 游戏AI的决策部分是比较重要的部分,游戏程序的老前辈们留下了两种经过考验的用于AI决策的结构: 有限状态机 行 ...

  6. Excel阅读模式/单元格行列指示/聚光灯开发 技术要点再分享

    1. 引言 文题中所谓技术要点再分享,本意是想在大神Charltsing Liu的博文“简单介绍Excel单元格行列指示的实现原理(俗称聚光灯功能)”的基础上写一点个人开发体会.写本文的初衷有三点,一 ...

  7. 游戏AI玩伴,是“神队友”还是“猪队友”?

    “一代英豪”暴雪迎来了自己的暴风雪. 2月13日,动视暴雪公布了2018年全年财报.财报显示,暴雪第四季度营业收入仅为28.4亿美元,低于华尔街分析师预期的30.4亿美元.在公布了财报业绩后,该公司又 ...

  8. 王亮:游戏AI探索之旅——从alphago到moba游戏

    欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~ 本文由云加社区技术沙龙 发表于云+社区专栏 演讲嘉宾:王亮,腾讯AI高级研究员.2013年加入腾讯,从事大数据预测以及游戏AI研发工作.目前 ...

  9. 游戏AI的生命力源自哪里?为你揭开MOBA AI的秘密!

    欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~ 本文由wataloo发表在专栏wataloo的试验田 1 设计概要 1.1 设计原则和目的 英雄AI的目的主要有: 1.新手过渡局,让玩家刚 ...

  10. 游戏AI的综合设计

    原地址:http://www.cnblogs.com/cocoaleaves/archive/2009/03/23/1419346.html 学校的MSTC要出杂志,第一期做游戏专题,我写了一下AI, ...

随机推荐

  1. 基于uniapp框架开发飞书小程序总结

    前期准备 飞书官方客户端文档:https://open.feishu.cn/document/home/intro 飞书官方工具资源文档:https://open.feishu.cn/document ...

  2. mysql自动生成时间

    字段类型: DATETIME 默认值: CURRENT_TIMESTAMP

  3. Esp32 arduino 编译报 hwcrypto/aes.h: No such file or directory 错误

    由于hwcrypto/* 在新版中移动到了 esp32/*. 编译会出现hwcrypto/aes.h: No such file or directory 的错误 解决方案如下: arduino 中E ...

  4. AI基本知识

    一.什么是flops 对flops有疑惑,首先得先捋清这个概念: FLOPS:注意全大写,是floating point operations per second的缩写,意指每秒浮点运算次数,理解为 ...

  5. iOS学习十一之步进控制器UIStepper

    步进控制器也就是进行离散式数据调节的常用视图控件. 在viewDidLoad()方法中加入下面的方法,即可完成基本功能. override func viewDidLoad() { super.vie ...

  6. edge 浏览器部分功能

    模拟打印情况的调试

  7. 2022 ICPC沈阳合肥游记

    选赛区的时候很争议,除了沈阳是确定要选,队友对于合肥新赛区的看法很质疑,但我想选合肥,一是觉得人少,二是觉得强队会少,因为隔壁CCPC.然后就选了合肥,看情况选合肥确实很对. 一开始也不认为会拿牌,后 ...

  8. Parallels Desktop 18(Mac虚拟机)v18.0.0(53049)无限试用版+win11系统

    Parallels Desktop 18 for Mac 是一款强大的虚拟机软件,让您无需重启即可在 Mac 上运行 Windows 应用程序不会减慢 Mac 的运行速度,具有速度快.操作简单且功能强 ...

  9. Markdown基础学习

    Markdown学习 一级标题 #加空格 标题二 二级标题 ##加空格 如此类推 标题三 或者Ctrl+123456 字体 加粗 两个** hello world 倾斜一个* hello world ...

  10. mysql创建数据库,用户,授权基操

    # 创建数据库create database test; # 创建用户并设置密码 create user 'test'@'%' identified by '123456';# 设置密码SET PAS ...