《DFQ》开发随录——AI

  欢迎参与讨论,转载请注明出处。

前言

  DFQ是PVE(Player VS Environment)游戏,那么自然要有AI了。DFQ的AI实现并不算复杂,并没有用到时下流行的行为树(Behavior Tree)。原因在于不需要做到太精细的操作,且AI部分的业务不需要执行策划参与(不需要编辑器化)。本文将一一叙述其中要点,相信对于同类型的游戏也有一定的参考价值。

宗旨

  AI设计的宗旨只有一个:根据游戏的各种情况,决定进行怎样的操作。这样的思路其实挺仿生的,我们玩游戏的时候本质上也是如此。要注意的是,玩家进行操作的方式是通过外设(键盘鼠标手柄触控等)输入操作信息(按键坐标等)。从这点来说,AI也可以这么做,以进行虚拟的输入操作。这么做的好处是很明显的,如此AI与玩家在功能上达到了一致,AI也不需要与某个具体的功能耦合,只需要关注相应的操作指令,无需关注具体的功能实现
  而这一切只需要做一套操作模块即可,并且做联机时来自其他玩家的输入亦可如此处理,通过这种方式达到了玩家、AI、联机三者的有机统一。可谓「软件开发中遇到的所有问题,都可以通过增加一层抽象而得以解决」的一次实践。
  当然这也会引入新的问题:某些功能只想AI拥有,那该怎么办?DFQ中的非转向移动便属于这类,解决方法很简单:设计一个玩家无法触发的操作指令即可。

对象

  AI的实体存在就是个类对象(下文称AI对象)而已,它会被外部调用的基础函数只有两个:Update和Tick。Update用于处理持续性的业务,而Tick则是一次性的业务,当然两者可能会有所结合(Tick接收参数,以驱动Update的运作)。
  AI对象主要会存在的场合有:常驻(移动和攻击)、技能(判断是否应发动)、状态(某些状态下需要后续的操作),通过配置化的方式,即可灵活的组合需要的AI了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
return {
script = "base",
state = "attack",
ai = {
script = "battleJudge",
collider = "duelist/goblin/skin/3-attack"
},
attackValues = {
{
damageRate = 1,
isPhysical = true
}
}
}

  如上配置所示,这是个技能的配置。在AI部分选择了battleJudge类,并提供了用于判断范围的collider参数。如此便定下了该技能的AI方针:使用collider判断是否存在敌人,存在则按下技能对应的按键,以发动技能。

实现

  说完基本构成后,再来说说一些具体AI业务的实现吧。

  • 移动:移动AI的核心构成有三
    • 获取目标:遍历符合条件的对象,涉及到阵营等因素。
    • 寻路:以目标为终点展开的寻路,由于DFQ使用的是网格地图,所以使用A星之类的寻路算法即可。
    • 输入操作:获取到移动路径后,通过发出输入指令以驱动角色以之移动。要注意的是,这种方式不可能做到完全贴合路径,所以出现了超过了路径点的情况也不会作处理。
  • 攻击:攻击AI要做的事情很单纯,遍历技能以Tick它们的AI对象进行发动而已。要注意的是,技能的使用顺序要建立优先级进行排序。
  • 判定:这个判定,便是上文的battleJudge了,通过collider以判断目标是否存在。这里的collider便是先前打击感所言的立体矩形,如下图所示:
    collider

  以上便是DFQ里值得一提的AI业务。顺带一提的是,AI是典型的不需要立即生效的业务,所以可以考虑每帧只执行一个单位的AI业务,以此减缓性能压力,并且避免敌人一窝蜂展开攻击的现象。

后记

  在本文开篇时,输入AI二字的我其实有点恍惚。短短数年,AI几乎成了深度学习/机器学习的代名词了。在游戏领域一个理所当然的缩写反倒让我踌躇了一瞬,真是唏嘘啊。也许以后的游戏AI真的都成了基于强化学习的实现也说不定呢(笑。