逼真的2D游戏战斗AI

图片

尽管“封闭区”主要是一种多人游戏,但是在互联网连接状况不佳或没有其他在线玩家的情况下,仍然必须存在复杂的AI机器人,以保持玩家的游戏状态。此外,机器人在某些游戏模式中起着重要的辅助作用。因此,他们应该表现得可信,并表现出一系列复杂的行为,包括使用掩体,在适当的时候使用物体,绕过侧翼,投掷手榴弹并逃离它们。

环境与限制


游戏环境由多边形组成。大多数多边形会阻止移动,可见性和射击,但也有一些“低级”多边形只会阻止运动。环境被障碍物和庇护所紧密覆盖。

AI也受到几个技术因素的限制。其中最重要的是:在网上没有多少玩家的情况下,执行bot的服务器应在具有至少10个bot的廉价VPS上快速工作。另外,CPU负载应保持足够低,以允许同一VPS上的多个服务器实例,而不会超出CPU限制,并且不会引起VPS服务提供商的制裁。


图1:环境


图2:从玩家的视线看障碍物阻挡的视线(灰色区域对他不可见)

导航和可见性网格,一种战术搜索


漫游器使用由离散点组成的密集导航网格。网格的生成如下:首先,扩展并组合构成环境的多边形。在拐角附近添加了其他节点,因为这些位置最有可能是合适的避难所位置。然后对生成的运动空间进行三角剖分以生成网格。


图3:导航网格

由于机器人必须对路径进行战术搜索,因此导航网格必须包含可见性数据,该数据可以使我们快速检查节点是否包含所选敌人的庇护所。因此,每个节点包含一个24个字节的数组,每个字节代表一个预先计算出的节点与最近的障碍物之间的近似距离,该障碍物沿某个方向阻止了视场。


图4:节点中存储的可见性数据(蓝线)。每行代表一个单字节值,该值定义了给定方向上的可见性。

由于这些数据,您可以使用A *算法搜索图形在导航网格上,可以向已知敌人打开的节点的优先级较低,而无需进行昂贵的视线检查。为了检查某个节点是否向敌人开放,我们确定该节点到敌人的方向和距离,然后检查该距离是否小于存储在最接近该方向的数组元素中的距离。此外,我们可以检查敌人是否在看着该节点。然后,我们可以将惩罚因子应用于穿越对敌人开放的节点的移动成本,并且最终的路径将倾向于避免此类节点。

除了查找两个给定点之间的路径之外,相同的可见性数据还可用于其他“战术”行动。例如,该机器人通过执行广度优先搜索来寻找庇护所,并在找到受保护的站点后立即停止。视线测试用于验证该站点是否确实提供了庇护所。同样,我们可以通过搜索A *作为目标,从侧面产生攻击路径;同时,对目标射击锥内的开放节点处以高额罚款。一旦我们到达发射锥外的开结,搜索就会停止。 (这种方法的问题之一是,超出范围的机器人会不断尝试接近目标,因此显得过于激进;这可以通过设置A *启发式算法来解决。因此漫游器不会直接移动到目标,而是直接移动到距目标选定距离的任何节点)。

机器人的感觉和记忆


为了使机器人表现出令人信服的行为,它们不应看起来像骗子。换句话说,机器人使用的信息应类似于玩家拥有的信息。例如,障碍物后面的敌人应该对机器人不可见,就像对玩家不可见一样。


玩家可以通过两种方式检测敌人的位置:可以看到敌人,也可以听到自己的动作,射击或其他动作。

每个漫游器都会保留一个有关敌人注视位置和方向的已知“事实”列表。如果不进行更新,则十秒钟后将删除这些事实。当机器人可以听到或看到该敌人时,与特定敌人有关的事实就会更新。当机器人听到敌人的声音时,为了模拟不确定性,相应事实的位置会根据机器人发出声音的距离而在随机的方向和距离上从敌人的真实位置偏移(请参阅视频,1:28)。


图5:机器人记忆中的事实(粉红色圆圈)

行为树


在早期版本的Close Quarters中,AI使用了STRIPS,这是FEAR在2005年推广的解决方案。在STRIPS中,程序员没有预先定义不同AI行为之间的关系。相反,每个行为都包含二进制前提条件和结果的列表。每个机器人在世界上都有问题的状态,并使用图形A *中的搜索来找到实现该问题的行为顺序。该解决方案效果很好,但我觉得它对于我的应用程序来说太复杂了,更适合于AI,后者需要制定涉及许多不同行为的复杂计划。在大多数情况下,我已经知道机器人必须在何种情况下执行该行为或该行为,因此对该算法使用A *会不必要地浪费CPU资源。

因此,机器人现在使用简单的决策树和行为。在每种情况下,机器人都会从根开始绕树,直到达到行为为止。如果此行为与已经执行的行为相同,则漫游器会继续此行为。如果不是,则该机器人会启动该行为并开始执行它。

某些行为可能会“阻止”,也就是说,阻止机器人在满足特定条件之前反复遍历树。例如,这对于确保机器人在决定攻击之前能够掩盖它很有用。同样,行为可以相互“消灭”,迫使机器人重新走树并重新启动行为。例如,当机器人从手榴弹中逃脱,而又出现另一枚手榴弹危害选定的逃脱位置时,此功能将非常有用。


图6:当前使用的决策和行为树

一些次要行为被编码在其他更一般的行为中。例如,如果机器人试图攻击敌人并发现该敌人不在预期的位置,则它会假定该敌人现在可以位于何处,并计算一条新的攻击路径而不会离开攻击行为。

负荷分配


每个机器人不必在物理的每个框架中进行更新,即每秒更新40次。为了降低CPU成本,每个漫游器每秒仅“思考” 20次(如有必要,可以减少此次数)。因此,在每个物理周期中只有一半的机器人被更新。

使用手榴弹


一个严重的问题是机器人有意义地使用了手榴弹。使用手榴弹比射击更加困难,因为手榴弹会从墙壁上飞出,造成一定程度的破坏,并有一定的投掷时间。幸运的是,机器人无需完美地使用手榴弹,足够的说服力。

解决此问题的传统方法是预先计算导航节点中的手榴弹路径,但实施该方法后,每张地图的加载时间会增加几秒钟,这与我的目标相矛盾:``近距离区''应该在开始游戏后的几秒钟内将玩家投入战斗。

因此,机器人正在寻找机会使用手榴弹,实时计算手榴弹的路径。在每个周期中,攻击机器人都会在距选定目标方向60度以内的给定方向上检查几种可能的轨迹。如果沿行之有效的方法投掷手榴弹可以杀死目标并且目标超出范围,则机器人会投掷手榴弹。检查的方向在每个AI时钟中循环播放。


图7:由漫游器检查一秒钟的方向(浅粉色线条),并沿着当前测量中所选方向(明亮的粉色线条)测试轨迹(蓝色圆圈)。

也就是说,机器人会尽可能使用手榴弹,并且不会专门移动到投掷手榴弹的位置。但是,机器人选择的攻击敌人的路径通常是投掷手榴弹的明智路径。

这种系统的一个重大缺点是,由于受限制的方向指示数量有限,机器人失去了投掷手榴弹的机会,因此它们反弹出小的障碍物。最引人注目的是,这是在门口附近,机器人通常不认识使用手榴弹的可能性。通过在一帧中测试多个方向并因此减小被检查方向与下一方向之间的角度,可以解决此问题。

转向更多人类行为


这样的问题很快就变得显而易见:机器人太快了,无法扳动扳机,因为在一对一的战斗中很难击败它们。人类对视觉刺激的平均反应时间为250毫秒,但每秒20次跳动时,机器人的最大反应时间仅为50毫秒!

为了解决这个问题,我特意在机器人获得射击机会和射击本身之间增加了一个延迟,以使其反应时间与人的反应时间相当。

进一步改进


上面介绍的系统提供了强大的基础AI,但没有提供重大改进的机会。例如,现在机器人的空间思维受到其周围环境的限制,因此,尽管机器人通常试图绕过侧面的敌人,但它通常会错过大障碍周围的越侧路线。此外,漫游器仅大致了解队友的存在,因此有时它们会聚集在一个地方,而不是被分开并从侧翼绕开。

All Articles