什么是ai
在文章初期首先给要讨论到的ai做一下定性。
即什么是ai。ai即人工资能(Artificial Intelligence)在广义上讨论ai时有的人会认为所有机器表现出来的能被认为是智能的表现都是ai,但同时在讨论智能的时候会涉及到很多复杂的问题,如意识,自我,思维等,也就是我们时常说机器人会不会有自己的意识,意识到自己是机器人等等。
游戏ai的应用也是相对广泛和灵活的,任何能够以一种让玩家认为是智能的方式实现的,让玩家的游戏体验更加具有沉浸性和挑战性的内容,我们都可以称之为ai。其中有两个要点①玩家认为是智能的;②目的是让玩家的游戏体验更有沉浸性和挑战性
如游戏中的寻路,让主角或者npc像真人一样会朝着目标找到合适的路线并进行移动,也可以被称为是ai。根据玩家选项不同npc会进行不同的对话分支也可以算做ai的内容
会涉及到哪些内容
文章内容为游戏策划向内容,所以不会涉及到具体的代码实现。更多是一些ai基础知识,常用的ai制作工具如行为树、状态机等,以及一些策划向的游戏ai的方案
什么是ai(从运行流程理解)
很多人在游戏制作提到ai就会将其与行为树、状态机等划等号,包括本文其实更多也是在介绍这两者,但实际上他们并不是相等的,可以从多个视角来解析ai的表现和什么是ai这个问题
玩家视角:
从玩家视角来看,如上所述,任何能够被玩家认为是智能的表现都可以被称为是ai,怪物的行动,策略,npc会和玩家沟通,寻路等等,这些具体的行为会被玩家理解为ai
工具视角:
大多时候我们策划制作ai就是编写行为树和状态机等,所以会潜意识中将其划伤等号
运行流程视角:
实际上ai的运行和我们人类的思考一样(像现在很多ai技术都是想模拟人类的思考方式)在游戏的每一帧(游戏运行的最小时间单位,也可以是程序设定的时间间隔),npc都会对当前要做什么进行规划,即现在要去做什么,然后判断这个事情能做成吗,如果不能做成或者这件事情做完了,后续要做什么。
在这个流程中行为树或状态机等,就是在npc思考要干什么时把要做的事情告诉他,但显然在这个流程中,我们是用行为树,还是状态机亦或是单独写脚本去告诉ai现在要干什么都是没有区别的,这些都只是ai执行流程中将数据录入的方法之一罢了,并不会太影响整个ai的运行流程
在这个例子中只包括了规划内容,实际上ai还会包括具体执行,比如每个具体的节点的执行和一些执行流程上的打断情况。
但这里主要是想说明行为树和状态机等只是ai录入数据的方法之一,并不等价于ai,实际上ai还可以有更多设计内容和方向,行为树和状态机作为一种录入数据的方法也可以应用在很多非ai的内容中
设计ai的目的
正如上文所说,游戏ai是为了提升玩家的游戏体验,这一章节会列举一些常见的能提升玩家体验的ai设计方向,并不是ai设计的全部内容,但是是笔者认为相对比较基础的必要内容
感知信息
这里说的感知信息主要有两个方面:
①通过信息进行判断,即ai可以通过一些信息做出基本的判断。这不难理解,一个npc看到了前方出现了敌人那他就应该开枪,这一行为的前提就是他能够“看到”敌人
②以合理的方式获得信息,如上所说ai的目的是以让玩家认为智能的方式提升玩家的游戏体验,如上一条,npc看到了玩家所以开枪是符合定义的,但如果npc有无限的视野能够随时随地知道玩家的位置并且追过去击杀玩家,显然这样的ai太过“智能”了,对玩家的游戏体验也是毁灭性的
文章中会尽量通过一些具体游戏的案例方便大家阅读理解。
第二点提到的过于智能的ai,如王者荣耀的人机ai(早年玩的时候是这样不知道现在还是不是),当玩家打龙时,ai就会直接前往龙坑抓玩家,这是很符合游戏规律的,但ai并不是“像正常玩家一样获取某些信息后判断玩家可能在打龙,然后前往龙坑”而是只要玩家去了龙坑不管ai有没有获得相关的视野信息,ai都会前往龙坑
一致的反馈
这里提到的一致的反馈并不是绝对的,主要针对大部分ai情况。
玩家需要一定的规律来进行判断和制定计划,正如一开始的定义,ai的目的是为了提升玩家的游戏体验,现实中人的行动可能是极难预测的,但如果游戏中的ai也设定成极难预测,就意味着游戏难度和可控性(甚至可能出现无法通关的情况)都会很差。
同时随着现在ai发展,有的游戏已经开始通过接入chatgpt等方式让npc的对话不再时重复的,一定程度上和这里提到的一致的反馈有所冲突。但实际上尽管如此,在设计上还是会需要npc有一定的一致的反馈
一定的智力
这里同样是为了提升玩家的体验,如果ai过于智能如上所说能获得一些超越玩家的信息,那游戏体验将会很差,同样的如果ai过于弱小,游戏体验一样会很差。
①过于弱小的AI,玩家无法从击败他获得成就感
②同时AI不笨并不意味着他就很聪明,AI的智力不应该体现在智力本身的强弱,而应该体现在“可信”的范围内(可以简单理解为符合玩家-正常人对其他人类行动的认知,合情合理)合理的犯错给于玩家机会,玩家出现大的失误时会抓住机会
常见的npc-ai制作方式(状态机与行为树)
这里只会介绍最基础的行为树和状态机的入门级基础内容
目前以及很长一段时间,游戏的npc-ai都是用状态机和行为树的方式制作的,其目的和表现整体上无太大差别,都是让npc或者怪物等游戏中的单位,能够以一定规律行动,或者是在一定情况下改变自己的运动状态(本来在巡逻,看到玩家进入战斗状态,击退玩家后回到巡逻状态)
状态机
状态机和行为树的本质目的都是更简单更方便的实现ai的方式,所以并不是绝对的方式,在后面的内容中也会提到这两者之外的一些方式,但这两者是目前最常见也是最基础比较方便策划理解的实现方式
什么是状态机
我们提到的状态机实际上指的是有限状态机(finite state machine,FSM),其内容为表示有限个状态以及在这些状态之间的转移和动作等行为的模型。如果完全没有相关知识不太理解状态机的定义可以看下面这个例子
在我们玩超级马里奥的时候,按下跳跃键角色就会腾空并摆出跳跃的动作直到落地,而当我们按住前进键角色就会播放奔跑的动作并移动。
这个流程用状态机来描述可以描述为:
①首先角色拥有三个状态分别是站立不动(Idle),跳跃(Jump),奔跑(Run),这三个状态都包括了一系列动作,如跳跃包括了跃起的动作,滞空的动作,落地的动作。而同时角色有着两个输入事件,跳跃键,和奔跑键
②角色一开始处于站立不动(Idle)的状态,当玩家输入跳跃键(事件)的时候,角色就进入到了跳跃(Jump)的状态,而当角色落地(事件)时又回到了站立不动(Idle)的状态
③同理,当玩家按住奔跑键时(事件),角色就进入了奔跑(Run)状态,在奔跑(Run)状态下松开奔跑键(事件),角色就恢复到了站立不动(Idle)的状态
理解了状态机的定义后就会发现,用状态机的“状态-事件”去描述游戏中角色的动作会更加方便,我们可以将各个动作都视为一个黑盒先不用去考虑里面是什么动作只需要先考虑清楚角色有什么动作,这些动作状态之间切换的条件是什么,就可以完成一个简单的动作循环设计,然后再去设计具体的每个状态机内动作的序列是如何的
状态机的特点可以总结为以下几点
-
只有有限的状态数量。对于马里奥的例子来说:只有站立,跳跃,奔跑这几个状态。
-
状态机某一时刻只能处于某一个状态。对于我们的例子来说:我们的角色不能同时处于跳跃和站立状态。实际上,也是为了阻止这种情况,我们才选择使用有限状态机。这一点其实也是很好理解的
-
会有一系列输入或者叫事件被状态机处理。对于我们的例子来说就是玩家按下或松开某个按键。
-
每个状态可以支持一组转换,每个转换由输入(或者叫事件)和目标状态定义。当有一个当前状态所支持的的输入(或者叫事件)到来,状态机会从当前状态转换到目标状态。对于我们的例子来说:当英雄处于站立状态时,玩家按下跳跃键,英雄会从站立状态转换到跳跃状态。对于当前状态所没有支持的转换输入到来,状态机会直接忽略掉。
而在绘制状态机的示意图时,我们通常会用方框,箭头,和箭头标注去描述状态机,如下图每一个方框代表一个状态,而箭头的走向代表了状态机之间可以进行的切换方向,而箭头上的注释则是切换条件。
关于状态机的具体更多类型的状态机和一些实现细节可以看后面的参考内容链接
行为树
行为树和状态机用途基本一致,一般情况下项目组会根据实际情况挑选二者之一(具体实现和表现优劣上会有一些差别)同时也有些可能会二者混用,都是可行的,但这里也是只会介绍行为树的基础入门内容
什么是行为树
我们在游戏中说的行为树(Behavior Tree)其实是一种决策树,与状态机相同他们都是描述游戏中各种单位行为逻辑的模型,但他并不以状态的概念去描述,如上所说其是以决策的结构来描述各种行为的,更确切的说是决策当前应该进行哪种行为
行为树绘制
行为树比起状态机可视化更强,如果是完全没基础的同学,直接从绘制图来了解会更加直接,如下图是ue中的行为树示意图,行为树顾名思义形状如一棵树一样(也有的是从左到右的,图示为从上到下的但道理都是一样的),行为树的节点根据位置可以分为两大类
叶节点:叶子结点顾名思义一棵树有着很多枝杈每个枝杈的末端就是叶子,同理叶叶节点就存在行为树的每个分支的末端,如下图中紫色的节点就都是叶节点
非叶节点:不是叶节点的节点就都是非叶节点
而之所以这样分类也是根据行为树的执行逻辑来分的,行为树会从上到下从左到右逐个去执行节点内容,而非叶节点都是判断用的节点(决策)只有叶节点才是具体的动作,如上图所示,只有叶节点是“move to”,“wait”等这些具体的命令,这就好比我们大脑思考一件事情经过一系列判断思考最终决定做某件事,只有最终的结果是具体的事情,而过程都是在进行逻辑判断
所以从执行上,也可以把行为树节点分为任务节点(Task,即叶节点),复合节点(composite,即非叶节点)。在执行上便是通过一系列复合节点进行逻辑判断最终找到我们要做的那个任务(这里的分类并不完备但如果完全没基础,此处先这样认为即可方便了解)
行为树执行顺序
行为树基础的执行顺序如上所述,从上到下从左到右逐个执行(也有的示意图是横过来的道理是一样的),同时行为树是一个不断循环的循环体,他会在自己的生命周期内不断循环执行直到生命周期结束。
除了基础的运行顺序外行为树还有执行成功与否的判断,即每个节点都会有一个返回值告知上一节点自己是成功了还是失败了,结合到游戏具体中的逻辑就是,如果成功移动到目标位置就开始待机。可以看出很多游戏的逻辑都是和前置动作是否成功相关的。
每个节点都会有一个自己的返回值,而复合节点虽然不具有具体的任务逻辑但其有着多个子节点,会根据子节点的返回值情况决定自己的返回值
行为树通过基础的运行顺序+通过复合节点对每个节点的返回值判断来进行行为顺序的控制
复合节点
复合节点有的地方也会叫为控制节点等等,都是顾名思义的,控制节点即控制行为树的运行顺序。此处会介绍一些常用的复合节点
复合节点如上如所示,可能会跟着多个子节点,而复合节点则决定了这些后续的子节点以怎样的顺序运行
选择节点(Selector)
选择节点:按默认顺序执行所属的子节点,若其中一个子节点返回成功则停止运行并且选择节点返回成功,如果执行完所有子节点都返回失败,则选择节点返回失败
同样顾名思义选择节点→选择一个子节点运行,当有一个子节点成功运行之后其他节点就不需要运行了,运行图示如下
在数学上的理解则是“或”||,多个子节点可以看为多个命题,命题之间是“或”的数学关系,则当有一个命题为真时,整个命题就是真了,后续的命题就不需要看了,而当所有命题都为假时,整个命题就为假
顺序节点(Sequence)
顺序节点:按默认顺序执行所属的子节点,若其中一个子节点返回失败则停止运行并且选择节点返回失败,如果执行完所有子节点都返回成功,则选择节点返回成功
同样顾名思义顺序节点→顺序运行所属节点,当有一个子节点失败,就不运行之后其他节点了,运行图示如下
在数学上的理解则是“与”&&,多个子节点可以看为多个命题,命题之间是“与”的数学关系,则当有一个命题为假时,整个命题就是假了,后续的命题就不需要看了,而当所有命题都为真时,整个命题就为真
复合节点执行逻辑小节
当了解了复合节点后,对行为树的运行应该已经大致理解了,这时候再看一开始的行为树图便能看出他的运行逻辑
首先从上到下是一个选择节点,即接下来的执行有一个是成功的就会结束运行,然后运行到下面是一个顺序节点,分别顺序执行“移动到某个位置”然后“等待”(假设两个行为都成功的话),然后顺序节点返回成功,最上面的选择节点有一个成功的子节点了,整个树结束一次循环,可以发现在这两个task一直保持成功的状态下是无法运行到后面其他状态的
这时候我们假设上述两个task中“move to”会因为各种原因失败,而此时顺序节点就会返回失败,然后最上层的选择节点就会运行到下一个子节点,也是一个选择节点,然后继续进行判断。
这时候就体现出了行为树的决策逻辑,策划预设好了判断的情况后,根据实际场上的情况变化(task返回不同值)从而做出了不同的行动
条件节点/判断节点
在上文中对节点进行分类时曾提到,单纯的任务节点+复合节点的描述是不完备的,这里开始会补充说明其他常用的节点。
首先是条件节点/判断节点,意思为:判断一个条件根据这个条件的真假决定后续进行哪个分支。这类节点会有不同的实现和绘制表现如上文提到的ue中并没有用这两个节点,而是直接通过增加黑板值判断黑板值来进行条件判断,我们这里为了方便统一了解还是把他们当做单独的两个节点来讲(道理都是一样的)
如上所述条件节点/判断节点的组合表达了一种逻辑:当这个条件为真/假时执行不同的分支。结合到游戏的具体逻辑便可以描述为,当boss血量大于50%时进行战斗状态1,当boss血量小于等于50%时进行战斗状态2,显然我的这个表述中,条件节点就是“boss血量大于50%?”,而判断节点会有两个分支(有且仅有,一定要有两个且只能有两个)分别对应条件判断真和假的情况
而判断节点自身的返回值则是后续节点的返回值和条件节点判断的真假无关
注:当条件节点独立出来的时候,条件节点也会是一个叶节点,因为他不能继续连接子节点
装饰节点
装饰节点指一些运行的限制条件和运行方式的限制节点,这里不做过多展开更多是根据项目实际情况进行拓展,这里只举例集中情况
如
取反节点:顾名思义将节点的成果失败结果取反,返回成功的变成返回失败,返回失败的变成返回成功
重复执行节点:意味后续的子节点们会循环执行指定次数(行为树本身是个循环体,相当于内部加入一个指定循环次数的循环体)具体游戏应用如:npc在四个定点间巡逻,循环五次后睡觉,睡醒后再进行巡逻
需要注意的是,很多设计中,如ue中的行为树并不会有独立的装饰节点node,装饰节点是装饰-节点之用,所以是附加在节点上作为这个节点本身的判断条件,如我在一个选择节点上附加了执行两次的装饰节点,这个时候这个节点的意义就变成了“执行两次的选择节点”,最终还是一整个节点,而不是先运行了限制的装饰节点然后再运行选择节点。
所以在示意图中也会把装饰附加在节点中而不是一个单独的节点
任务节点
任务节点在策划层面并没有太多内容,因为更多是指定各类动作让程序实现即可,但这里会有一个和状态机不太一样的运行方式
状态机执行一个动作时会是一系列动作执行并维持在状态机内部一直执行直到出现可以让他改变的事件,而行为树并没有这样的小循环概念,就出现了另一个概念“阻塞”
意义在于举个游戏实际例子:
①当角色执行说话这个动作,当他开始说话这个动作,就完成这个节点执行了,会进行后续移动了(开始说话然后移动,整体是边说边走)
②而另一种情况是需要等说话节点完成了,再进行移动(说完话再移动,整体是站在原地说完了再开始走)。
这两者的区别就是“阻塞”,第一个描述中就是没有进行阻塞,而第二个例子中则是说话节点进行了阻塞,即要等待到这个节点执行完成才会有节点返回值,才会继续进行接下来的节点流
行为树设计基础
行为树信息传递
在游戏中ai会通过各种感知器官(sensors)获得信息然后做出判断和行动,但在实际上感知和行为树之间还有数据存储,整个结构如下
如图中所示,当感知器官得到信息后会对数据库/黑板值进行修改,而行为树则是读取数据库/黑板值的数据进行判断。所以在设计完整的行为树系统的时候,还需要对会用到的数据和感知系统的对应关系有基本的设计。
如假设制作一款潜行游戏,我们为了判断玩家是否出现在了ai的视野中,需要在数据库中定义一个布尔变量假设叫做“看到玩家了吗?”,这个值默认为“否”,要等到感知系统获得了“是”的信息才会进行修改。然后就会来到感知系统,何种情况下感知系统会将数据库的这个布尔变量变为“是”。可以是由npc做射线检测碰到玩家即代表看到了。而行为树中只需要设计判断布尔变量并进行不同的行为即可。
我们也可以设计的更加复杂一些,在数据库中增加一个名为“警戒度”的数值变量,当感知系统的射线碰到玩家后不会修改布尔变量,而是不断增加警戒度,当警戒度达到100时,将布尔变量修改为“是”,而当感知系统判断丢失视野时,ai也不会将布尔变量改为否,而是警戒度不断降低,直到警戒度到达50以下。行为树中的内容也需要对应的变为判断布尔值和警戒值,如果需要在不同警戒值表现出不同的效果也可以增加判断
以上主要是举例一两种比较简单的设计来体现游戏设计和这里数据结构设计的关联性,在制作实际项目时会有更多系统和更多想法,自然也会有更复杂的设计。这里总结了一些在使用或者设计行为树时需要注意的点。
数据定义
具体用到的数值变量如上所述其实是根据项目组需求而定,但也有一些比较通用的注意点
简单
数值的定义最好是简单的,如上例子中是或否的布尔变量,数值等,简单的数值类型能让策划在后续进行行为树设计时更近方便。
一致
在设计上保持一致,参数的命名使用等,这会让其他人更容易接手快速理解,在后期整理拓展时也更加方便
分类
在简单的同时也需要进行必要的分类,很多时候会用到字典类型,可以理解成有许多数据其实是跟具体的单位相关的,比如我需要记录某一个特定的npc他的血量,这个时候就需要有一个字典名为这个npc,而这个字典下记录着和这个npc相关的各类数据。不仅如此也可以将这个对象进一步抽象,在涉及战斗或者对话中时我们的对象往往是抽象的,比如技能释放者,击中者,说话者,倾听者,显然这些单位都不会是某一个固定的单位,我们也可以为他们设计抽象的对象分类,一个名为speaker的字典,当一段对话开始时存储说话者的信息
行为树与状态机的选择
在游戏制作中两种循环体都是经历了大量验证和使用的,这一部分将会简单介绍两者之间的部分差别以及取舍
状态机如上所述也顾名思义,更加擅长对于“状态”的描述,但也如上面展示的,他的示意图更多展示了状态之间的切换,对于策划(大部分人)来说很难通过示意图快速的了解这个ai的行为是怎样的很难关联想象
而行为树则更加擅长对于动作序列的描述,正如上面所说先干什么再干什么,示意图的流程也更加易读,在了解了行为树的基本运行原理后行为树的示意图可读性是远大于状态机的。而行为树在运行上会需要不断地去遍历各个节点直到找到自己要进行的节点,这在一些大型游戏中将是致命的,试想如果是一款割草游戏,场内有几千甚至上万个单位都在每帧都进行着节点遍历,那卡顿显示是必然的结果
二者各有优劣在实际项目中也存在二者混合使用,在适合的地方使用合适的技术。
除此之外,虽然本文都是以npc的个体ai作为例子举例,但实际上行为树和状态机只是两种用来进行ai方案的循环体,并不会仅仅局限在个体ai上,也可以用作群体ai,战术ai等多单位ai设计上。甚至于可以不给npc分配具体的行为树或状态机,策划设定好部分行为树和状态机,在游戏中通过预设的规则将行为树/状态机动态的分配给npc,实现更加真实的ai表现
参考内容链接
什么是ai:《AI for Game Developers》 – David M. Bourg, Glenn Seeman
状态机:
原文链接:https://www.bilibili.com/read/cv26229171/