《Unity3D高级编程之进阶主程》第八章 AI(3) 非典型性AI

前面讲了状态机和行为树在AI中的运用,在实际开发过程中,特别是一些在游戏行业做过5-10年左右的很多人似乎似乎已经习惯了用这些固定的工具去写AI逻辑,一想到游戏AI就固定思维的认为,就用状态机去写,或者说就用行为树去写。

思维跳不出这些‘工具’,我们就成不了大师。大师是什么,是能将‘剑’运用到最高境界的人,手里‘无剑’而心中有剑,是他们的至高境界。万事万物都是同一个道理,‘技术’就像剑术,在练习过程中,都会经过几个阶段,到底具体有哪些阶段每个人都不一样,我能确定的是,‘识剑’是第一个阶段,认识剑是怎么样的,或者说认识‘技术’是个怎样的东西用在哪里。而‘用剑’是另一个阶段,如何用剑或者说如何运用这项‘技术’是大多数人停留的阶段,怎么用剑怎么用好剑,是一个非常漫长而枯燥的阶段。‘无剑’就是最后一个阶段,手里没有剑而心中有剑在剑术的造诣上达到了至高的境界,无剑胜有剑在这个阶段体现的淋漓尽致。

我们接触的面要尽量的广,接受和包容的东西要尽量的多,才能体验到更多的东西。游戏开发也是,世界上不是只有RPG角色扮演类一种游戏类型,还有SLG策略类游戏,还有休闲娱乐类游戏,还有体育竞技类游戏,还有学习教育类游戏等等等。只有状态机,只有行为树,或者只有状态机和行为树是无法为项目开发出最好最适合的AI的。我们应该尽量包容非典型性AI。

===

下面我们来了解下游戏项目中非典型性的AI。

1,庄家式AI

顾名思义,是庄家统治游戏的一种玩法,玩法中AI就是全局的统治者,它决定了整个游戏的高潮和低谷,AI如何操作成为了至关重要的关键点,玩家是否喜欢这款游戏很大程度上取决于AI的策略。

这种类型游戏大部分以彩票或赌局的形式存在,比如老虎机,百家乐,21点,以及部分以彩票为形式的游戏。

AI策略的目的是要让玩家玩的好又不能赢太多而且最终是要输给AI的。玩家喜欢继续玩但从总体上来看却又是输的,让庄家就是游戏运行商有的赚,但又不能太狠,让游戏细水长流。

这种AI常以输赢的概率为基本控制手段,比如现阶段以玩家欢乐为主,那么胜的概率变得大一点,玩家会认为幸运女神眷顾他了,一段时间后为了让玩家遇到点困难,让玩家有挑战性,这时AI慢慢降低了赢的概率,玩家缓慢觉得赢的次数开始减少,有些玩家会以为幸运女神走了,需要靠自己的‘本事’玩下去了,他们不断得发现和寻找输赢的规律,以及出牌和翻牌的概率,直到输得所剩无几,然后AI开始了缓慢提高胜率的操作,让玩家又看到了希望,找到了自信,认为自己终于不费苦心找到了规律和破解的秘密,于是又开始了一轮有输有赢但赢多输少的旅程。

如此这般不断得循环往复,AI以一种庄家的形式控制着整个游戏过程。

从技术上来看,这种控制概率的过程,就是加法和减法的过程,相对比较简单。其核心是给出一个概率后,如何让它真的起到概率的作用,而且这种概率能让人很舒适的接受,比如当有30%概率赢时能否做到真正的随机值在30%的概率上徘徊,比如10局中有2-4局能中玩家可以得到想要的那个点位或者想要的牌什么的,而不是10局中0-5局能赢,输赢实际结果波动到了不好的体验。

2,可演算式AI

可演算式的AI在策略类游戏中非常常见,在页游里的大部分的自动对战,以及现在卡牌手游中的大部分自动战斗都是可演算式的AI,是可以根据两边的阵容数据和一个随机种子来演算出整场战斗的每个细节的。例如,两个军队的各5个英雄,互相间攻击并释放技能,服务器需要在一瞬间把所有需要在客户端演示的内容都计算出来,并以数据的形式发送给客户端,客户端根据演算的数据进行展示人物的动作,位移,技能释放等,客户端并不需要计算任何内容,所有内容都在服务器里已经计算好了,以数据形式代表了整个过程。

可演算式AI的特点是逻辑一定是确定性的,不能是模糊的,或者会随机改变的,或者随时间变化而变化的结果,同样的数据第一次计算和多次计算的结果必须是相同的,才能最终体现出可演算的这个特征。

其次,可演算式AI大都是根据时间轴来演化游戏的进程,在那里‘时间轴’的概念在可演算式AI中是比较常见的。

什么是时间轴演算路径?我们用卡牌对战算法来举几个例子。

首先最简单的时间轴演算路径,例如,先由敏捷度最高的英雄进攻,等待英雄进攻完毕后再由其次高敏捷度的英雄进攻,依次进行下去直到所有的英雄进攻完毕再重新一轮进攻。这种相对比较简单,可以把进攻看成一轮一轮的回合,每个回合都相当于是一次for循环,每次for循环前先对敏捷度进行排序,再在for循环中依次计算进攻了谁受到了多少伤害,以及是否死亡。最后把进攻的数据和伤害的数据用队列的形式存储在数据中发送给客户端,客户端受到数据后再进行演示。

稍微复杂点的时间轴逻辑,例如,不再由敏捷度来决定进攻的先后次序了,而是由每个英雄的进攻间隔冷却时间来决定进攻次序,对战开始时开始计算每个英雄的进攻冷却时间是否结束,谁的冷却时间先结束谁就最先得到进攻权,进攻完毕后再等待下一个英雄的冷却时间,以此类推。从技术上讲,冷却时间不需要等待,把所有英雄加入一个队列,排序一下就可以得到谁的剩余冷却时间最短,就立马可以开始计算进攻细节,完毕后根据冷却时间插入到队列中去,任然还是一个有序的剩余冷却时间队列,一直这样计算下去直到演算结束一方胜利或失败。这种演算方式就有了更多了时间轴的概念。

再稍微复杂点,前面所说的进攻逻辑都是在其他英雄都停止的状态下进行的,现在进攻时不再需要其他英雄等待了,一旦冷却时间结束就可以立刻进攻。也就是说,每个英雄都可以在其他英雄还在进攻时进行进攻操作,只要他的冷却时间到位,并且他的进攻时需要花费固定时间的,等到进攻完毕后再判断对方和自己是否死亡。这种方式,不只是多了一个进攻消耗时间这么简单,还多了一个死亡判断时间,在还没有死亡判定前,此英雄虽然是死了但任然可以被进攻。从技术上来看,计算的量从单一的剩余时间量排序,增加了进攻消耗时间排序插入,以及死亡判定排序,我们既要在冷却时间结束时计算进攻,还要在选择进攻对象时计算该英雄是否已经判定死亡,最后在进攻完毕后计算当前的时间并插入到排序队列中。

再复杂点,英雄在进攻一半时可以被别的英雄打死,也可以被其他英雄的技能打断,也包括了随时被回复血量蓝量,增加状态等等,让战斗更加逼真、更具有实时性。加强了实时性的要求,更加考验可演算式AI的复杂度,由于太多的需要计算的时间内容,所以我们必须有一个能有效管理时间轴的方法。从技术上来看,我们必须定义‘时间节点’这个概念了。

什么是‘时间节点’?‘时间节点’就是一个事件在整个过程的时间轴上的发生时的位置。

有了时间节点这个概念,我们可以用时间节点为计算标准,把所有人物的下一个事件的时间节点计算出来,比如,移动到达敌方位置,又比如,释放技能,又比如,回到原地,又比如,冷却时间结束,每个人只计算最近的一个时间节点,并把计算出来的结果放进队列中,然后就可以找出时间节点里离我们最近的一次事件的发生节点,也就是时间差最少的节点,执行它。

由于每个时间点都有可能引起其他时间点的变化,比如把对方打死了,对方的时间节点就消失了,又比如打断了别人技能释放,对方就回到了冷却时间,时间节点就需要重新计算了,又比如加速了友军的攻击速度,因此所有友军正在攻击或打算攻击的时间节点都要重新计算了,等等等等。

所以每次在执行完一个时间节点后,都要对有可能产生变化的人物的时间节点进行重新计算,并加入队列,然后就可以找出离我们最近的一个时间节点了,当然旧的时间节点数据必须清除掉。

如此往复的重复这个计算过程,直到没有任何时间节点可计算和执行,最终决出这张战斗的胜利或失败。

时间轴贯穿了整个AI过程,人物之间的打斗,移动,释放法术,冷却时间等待,AI每次只计算一个时间节点,因为只有最近的那个时间节点是一定不会被其他节点影响的,这样既照顾到了可演算的根本原则,也照顾到了游戏的实时性,让战斗更加精彩。然后把每个计算的结果都记录下来,就可以在客户端进行演示了,整个过程的事件发生的时间都将准确无误呈现出来。

3,博弈式AI

游戏项目中大部分AI的目的都是以娱乐玩家为主,并没有要真正打败玩家,最多也是要与玩家达到一种平衡。而博弈式AI则不同,它的目标就是为了打败玩家,它是为了赢得比赛而生的。

博弈AI最大的特点是搜索。通过搜索,将所有下一步可能发生的,以及下几步可能发生的事情都记录在内存中,以此来确定电脑该怎么进行下一步动作,进而获得最大的效益。

有的人不理解为什么是搜索,这里稍微做下解释。在AI选择下一步的动作前,下一步要发生的情况有很多,我们需要选择最佳的那个,怎么选择呢?把所有下一步的情况都列出来,再把下一步的后几步的情况也列在下一步的下面,由于cpu计算量的限制后面的几十几百步计算量太大以至于无法计算,假设我们只计算和预测十步的结果,我们需要找到第十步的最好结果,再反推到第一步来确定第一步到第十步是怎么走的。

把这十步的所有结果都计算出来太耗时CPU负重太大,有些甚至无法承受这样大的计算量,那么我们就要在没有结果的情况下得到最佳选择,怎么做呢?既然我们要从第一步走到第十步,假设第一步有10种情况,第十步有10种情况,每一步之间都有一个结果就相当于一点到另一个点的路径一样,从第一步到第十步就可以视为路径的一种,那么从第一个点到第十个点的最短路径,就是第一步到第十步的最佳结果。把视角一转换后发现事情变得的简单了,用最短路径算法就可以解决搜索问题。

不过事情远没有这么简单,这里只是举了个简单的例子,情况会复杂到每一步有几百种情况,普通的搜索方式计算机可能完全无法承受。为了能让计算机承受这样大的计算量,我们就需要引入更多的枝剪和优化,比如,存储一些固定技巧,以及拒绝计算一些明显比较差的选择。

另一个特点是AI对局势的估值该如何认定。估值表示了当前局势的好坏程度,通常用一个0到100的浮点数来表示估值,估值的好坏是AI一个比较关键的点,只有正确的计算出局势的估值,AI才能知道选择的行动方向是正确的还是错误的。

拿最简单的五子棋来说。棋盘上的每一个点都是对手下一步的可能性,通常不会在空白处下一个完全不着边的棋,所以搜索范围缩减到了当前棋盘上有棋子的范围周围的空位。AI对所有这些空位录入并计算当AI把棋子放入该位置上后,对方可能做出的反应以及由此引发的后几步的对弈可能。我们假设AI只搜索和计算后5步的预测,也就是说,计算出来的当前落子的估值,就是所有棋盘中可落子的后5步内最优估值。

最后一个特点是数据录入。人类的手法太过高明,欺骗性很强,很容易就能躲过AI的盲点,所以录入特别的人类的想法的是博弈AI的一大关键点。没有数据的录入,AI很难知道人类的想法。

96年97年的人机国际象棋大战就是录入了大量的棋局来告诉AI人类的一些固定走法,让AI在对弈中识别人类的套路。

以前的数据是一些人手动录入的,所以局限性还是很大,不能应付现代这么快更新换代的技巧和想法。为了做出更强大的博弈式AI,我们不得开始让AI拥有自学的能力,所以机器学习,深度学习得到了广泛的关注和应用。它们原理就是数据录入,加,估值判定,给AI不断地喂数据的同时,告诉AI这个数据是对的还是错的,或者说估值能达到多少,通过不断的喂数据(也相当于用数据训练AI)的方式,让AI拥有丰富的‘经验’,从而在对弈中赢得比赛。

感谢您的耐心阅读

Thanks for your reading

  • 版权申明

    本文为博主原创文章,未经允许不得转载:

    《Unity3D高级编程之进阶主程》第八章 AI(3) 非典型性AI

    Copyright attention

    Please don't reprint without authorize.

  • 微信公众号