您的位置:首页 > 大数据 > 人工智能

游戏行业的人工智能设计

2017-05-08 13:37 281 查看
转自:http://www.gameres.com/749367.html

第一部分: 设计和实施

  对于游戏行业而言,人工智能是什么?

  从最基本的层面而言,“人工智能”包括模仿其他玩家或玩家所代表实体(即可以响应或付诸实践的所有游戏元素——从玩家、飞弹到健康皮卡)的行为。 关键概念是模仿行为。 也就是说,游戏行业的人工智能更加人工化,而智能程度较低。 系统既可以是基于规则的简单系统,也可以是旨在挑战玩家作为对立军队指挥官的复杂系统。

  游戏行业的人工智能与传统的人工智能观点有何不同

  对人工智能的传统研究旨在创建真正的智能——尽管是通过人工手段。 有些项目,如麻省理工学院 (MIT) 的Kismet* 项目,正在尝试创建一种能够进行学习、社交互动并表现情感的人工智能。 在本文撰写之时,麻省理工学院正在创建一种有幼儿教师和可喜成果的人工智能。

  对于如今的游戏而言,真正的人工智能已经超出了一款娱乐软件的要求。 游戏人工智能不需要具备感受力或自我感知能力(事实上没有最好);它不需要了解除游戏之外的任何信息。 游戏人工智能的真正目标是模仿智能行为,为玩家提供一种可信的挑战——即玩家可以克服的挑战。

  游戏人工智能的目标

  人工智能可以在游戏中扮演多种角色。 它可以是一套用于管理游戏世界中实体行为的一般规则。 您也可以考虑实体遵循一类人工智能的预制脚本事件。 例如在游戏 F.E.A.R* 中, 用于恐吓玩家和预示未来事件的令人毛骨悚然的小女孩就是一个预制脚本事件。 提到人工智能和游戏时,大多数人都会想到多人游戏中由电脑控制的玩家。 不过,所有这些都是人工智能能够实现的不同角色。



图 1: F.E.A.R.(Vivendi Universal)在一类人工智能中使用脚本事件

  游戏人工智能的基本要素

  根据人工智能要实现的角色的性质,系统需求可能非常少。 系统越复杂,人工智能的要求就越多。 基本需求无非是运行 AI 所需的处理时间。 更复杂的系统需要一些感知人工智能环境的手段,玩家行为记录和一些评估先前决策成功度的手段。

  决策

  人工智能背后的核心概念是决策。 为了执行这些选择,智能系统需要能够使用人工智能系统影响实体。 您可以通过“人工智能推送”或“实体推送”战略管理这一执行。

  人工智能推送系统通常将人工智能系统隔离为游戏架构的独立元素。 此类战略通常采取独立线程或线程的形式,线程中的人工智能花时间计算给出游戏选项的最佳选择。 当人工智能制定决策时,这一决策将随后传播至涉及的实体。 这一方法在实时战略游戏中最有效,因为在这种游戏中,人工智能关注大局。

  实体推送系统最适合包含简单实体的游戏。 在这些游戏中,实体会在其“思考”或自我更新时调用人工智能系统。 这种方法非常适合于包含大量不需要经常思考的实体的系统,如射手系统。 这一系统还可以从多线程技术中受益,但需要一些额外的计划(详情请见Orion Granatir 的多线程人工智能上的文章)。

  基本感知

  为了使人工智能作出有意义的决策,它需要感知周围环境的某种方式。 在较简单的系统中,这种感知可能只是对玩家实体的位置进行简单的检查。 随着系统的要求越来越苛刻,实体需要找出游戏世界的主要特点,如可行的穿行路径、提供掩护的地形和冲突地区。

  设计人员和开发人员面临的挑战在于找出一种方法,以确定对智能系统至关重要的主要特点。 例如,掩护可以由关卡设计师预先确定,或可以在加载或编译地图时进行预先计算。 有些元素可以动态评估,如冲突地图和紧迫威胁。

  基于规则的系统

  智能系统采用的最基本形式是基于规则的系统。 这一系统延伸了“人工智能”这一术语。 一组预设行为用于确定游戏实体的行为。 对于各种行为,总体结果可以是一个虽然涉及的实际智能很少但并不明显的行为系统。

  在基于规则的系统方面,Black Jack 庄家就是一个很好的例子(无论是视频 Black Jack 还是真正的 Black Jack)。 庄家遵循一个简单规则: 当牌点数为 17 或不到 17 时必须要牌。 一般玩家的看法是庄家有竞争力。 玩家会设想一个比其当前敌手更有能力的对手(除非赌场经营者公布庄家遵守的规则)。

  Pac-Man 是这一系统的典型应用。 四个鬼纠缠着玩家。 每个鬼都遵循一个简单的规则集。 一个鬼一直左转,另一个一直右转,一个以随机方向转弯,最后一个转向玩家。 每个鬼的移动方向很容易弄清楚,玩家能够轻松避开他们。 但作为一个集体,这些鬼的移动方式看起来就复杂的多,相互协调配合共同寻找玩家。 事实上,检查玩家位置的只有最后一个鬼。



图 2: 控制Pac-Man 鬼的规则集的直观图,其中的箭头代表将作出的“决策”。

  正如本例所示,规则不需要硬编码: 规则可以基于感知到的状态(如最后一只鬼)或实体的可编辑参数。 进攻、勇气、视线范围和思考速度等变量均可以产生更多样化的实体行为,即使是在基于规则的系统中。 基于规则的系统是最简单的人工智能结构。 更复杂的智能系统基于一系列条件规则构建并由这些规则管理。 在战术游戏中,规则控制着要使用的策略。 在策略游戏中,规则控制着建造顺序和应对冲突的方式。 基于规则的系统是人工智能的基础。

  有限状态机作为人工智能

  有限状态机 (FMS) 是一种概念化和实施在整个生命周期中拥有不同状态的实体的方式。 “状态”可以代表实体所处的物理状态,或者也可以代表实体展示出的情感状态。 在本例中,情感状态并不是真正人工智能的情感状态,而是融入游戏环境的预定行为模型。

  下面是一个人工智能系统的常见状态示例,针对一个包含隐性元素的游戏:



图 3: 典型 FSM 中的状态布局,其中的箭头表示可能的状态变化

  闲置。在这种状态下,实体会被动地站着或沿固定路线走动。 感知水平低。 不常检查游戏玩家的声音。 只有这一实体受到攻击或“看到”玩家直接在其前面时,它的状态才会更改为较高的认知水平。

  感知。这一实体主动寻找入侵者。 它会经常检查游戏玩家的声音,比闲置实体看得更远更宽泛。 如果这一实体注意到碍事的某物(在其检查范围之内),如打开的门、无意识的尸体和用过的弹壳等,它将变为好奇状态。

  好奇。这一实体意识到发生了不寻常的事情。 为了证实这一行为,该实体将放弃其正常岗位或路线,移动到感兴趣的区域,如前面提到的打开的门或尸体。 如果玩家被发现,实体将变为警戒状态。

  警戒。在这种状态下,实体已经注意到玩家并将开展追捕玩家的行动:移入攻击范围、提醒其他警卫、发出警报并寻找掩护。 当实体在敌人范围内时,它将切换到攻击状态。

  攻击。在这种状态下,敌人已经参与到与玩家的战斗中来。 实体会在可能时攻击玩家,并在不同的攻击回合之间寻找掩护(根据攻击缓和时间或装弹时间)。 只有在消灭敌人后(恢复正常)、敌人移动到射程之外(回到警戒阶段)或实体死亡(进入死亡状态)时,实体才会离开这个状态。 如果实体的生命值很低,它可以切换为逃跑状态,这取决于特定实体的胆量。

  逃跑。在这种状况下,实体会试图逃离战斗。 根据游戏的不同,可能会有寻找生命值或离开游戏区域的次级目标。 当实体找到生命值后,它可能会返回到警戒状态并恢复战斗力。 “离开”的实体只是删除了而已。

  死亡。在有些游戏中,死亡状态可能不是完全闲置。 死亡或濒死的实体可能会“大声呼叫”,从而提醒附近的实体,或进入神志不清的状态,医师可使其复活(并返回到警戒状态)。

  在实体系统中实施 FMS 至少有两种简单方法。 第一种是让每种状态成为一种可以检查的变量(通常通过大量的开关语句)。 第二种方法是使用函数指针(C 语言)或虚拟函数(C++ 和其他面向对象的语言)。

  自适应人工智能

  前面的章节讨论了如何设计融入游戏预定义事件的智能系统。 对于大多数游戏而言,只要设计缜密且对智能实体的目标有清晰的认识,这就足够了。 如果游戏需要更多的变化并为玩家提供更好、更有活力的对手,人工智能可能需要具备增长和独自适应的能力。

  自适应人工智能通常用于格斗游戏和策略游戏,这些游戏具有深层次的机制和无数的游戏选项。 若要为玩家提供持续的挑战且避免玩家最终找出打败电脑的最佳策略,人工智能需要具备学习和适应的能力。

  预测

  有效预测对手下一步行动的能力对于自适应系统至关重要。 可以使用不同的方法,如过去模式识别(在未来的文章中介绍)或随机猜测,以确定要采取的下一步行动。

  适应的一个基本方法是记录过去的决策并评估成功程度。 人工智能系统会记录一个游戏玩家在过去所做的选择。 过去的决策必须以某种方式进行评估。 (如在格斗游戏中,获得的优势或损失的生命值或时间优势可以作为成功的衡量指标。) 可以通过收集有关这种情况的更多信息来为决策提供一些背景,如相对生命值、以前的行为和关卡定位(当玩家走投无路时会采用不同的游戏方式)。

  可以通过评估这些历史信息来确定以前行为的成功程度以及是否需要改变战术。 在构建过去行为列表之前,可以使用一般战术或随机行为来引导实体的行为。 这一系统可以与基于规则的系统和不同的状态相结合。

  在战术游戏中,过去的历史可以决定用于对付玩家团队的最佳战术,如防守、进攻、狂暴或一些平衡的游戏方法。 在策略游戏中,可以基于玩家发现一个部队中最佳的分队组合。 在由人工智能控制玩家支持角色的游戏中,通过了解玩家的行为方式,自适应人工智能可以更好地补充玩家的自然风格。

  总结

  人工智能是一个复杂的研究领域。 根据游戏需求的不同,游戏行业的人工智能会采用不同的形式,从计算机控制器实体的简单规则集到更先进的自适应系统。 在游戏行业中应用人工智能概念对于提高电子娱乐产品中虚拟人物的可信度必不可少,但它并不是一个不可能的挑战。 这一系列的下一篇文章将讨论人工智能在感知和导航复杂环境方面所面临的挑战,以及如何应对这些挑战。

感知和路径搜寻

  在上一篇文章(第一部分)中,我们讨论了如何管理智能代理可能作出的基本决策——因为人工智能 (AI) 研究涉及到使用人工智能的实体。 在本文中,我为游戏男主角(或怪物或任何类型的游戏实体)作出的决策提供了一些背景。 智能代理需要确定游戏领域的兴趣点,然后明确如何达到目标。 最后,本文还将介绍如何优化这些方法并提供管理它们的方法,以说明多线程。

  本文非常接近真正的人工智能 (AI)。 所有智能代理都需要具备感知环境的基本能力,并拥有在周围世界(无论是真实世界还是虚拟世界)中导航和移动的一些手段。 尽管方法有很大不同,但您的实体也需要具备这样的能力。 您也可以投机取巧,以确保一切快速顺畅地运行。

  人工智能的感知方法

  让代理作出武断决定适用于某些游戏,但如果您需要更多能力呢? 如果您的代理将作出适当的决策,那么它需要了解周围发生的事情。 在人工智能的机器人应用中,做了大量关于计算机视觉方面的研究,为机器人提供了以真实、立体的三维 (3D) 视觉感知周围环境的能力,就像人类一样。这种成熟水平对于我们来说是完全多余的。

  相较于真实世界的人工智能机器人,大多数游戏所用的虚拟世界拥有巨大优势。 我们世界中的一切都是已知量: 游戏中有一个列表,其中包含游戏里的一切。 您可以在这一列表中搜索任何标准,然后立即获取代理所用的信息,以制定更有意义的决策。

  视觉

  伪造实体视觉是为代理提供感知能力的最基本层次。 您可以通过在实体列表中搜索特定范围内的一切来做到这一点。 您既可以获取代理感兴趣的首要事件,也可以获取范围之内的事件列表,以便您的代理针对周围环境作出最佳决策。

  这一设置适用于简单游戏,但当您的游戏风格较复杂时,如间谍游戏或第一人称的战术射击游戏 (FPS),您的代理将需要在“看到”的内容上更具有选择性。 如果您不希望代理眼观四面,您可以针对超过实体视线范围之外的任意内容的潜力筛选出一个列表。 只需用一点数学知识就可以快速完成这一工作:

从代理的位置减去目标位置,计算考虑中的代理和实体之间的矢量。

计算矢量和代理所看方向之间的角度。(如果已经不是一个矢量,您也可以计算出数值)。

如果角度的绝对值大于代理的预设视角,您的代理看不到实体。

  在较复杂的游戏中,您可能需要考虑某种遮蔽物隐藏的玩家或其他实体。 对于此类游戏,您可能需要执行光线追踪 (有时称为光线投射),以了解是否有东西阻挡了潜在目标。 光线追踪是一种检查光线是否贯穿任何东西的数学方法,从一个点开始,以固定方向移动。 游戏引擎提供了光线追踪功能,但如果您想要了解其详情,请参见“三个臭皮匠抵一个诸葛亮”。

  之前的方法告诉您是否有东西遮盖了目标中心,但可能不足以阻止您的代理。 有可能代理的中心被遮蔽,但代理的上部在遮蔽物上方伸出。 在目标上的特定关注点使用多个光线追踪不仅可以帮助确定 能否击中目标,还可以确定能够击中目标的哪个位置。

  声音

  乍看起来,它可能像是与视线无异的声音。 如果您可以看到实体,您肯定也能听到。 的确,如果您的代理发现了实体,代理可以主动检测实体所作的任何事情,直到从视线中完全消失。 但是,为代理添加额外的听觉水平可帮助视觉更有效地工作。 跟踪实体发出的作为感知水平的噪声对于任何隐蔽类游戏都至关重要。

  和视觉一样,您需要获取一个附近实体的列表以便核对。 您可以再次通过简单的距离检查完成这项工作,但筛选这一列表的方式不同。

  实体执行的每个操作需要有一些与其相关的声级。 您可以预设声级(以优化游戏平衡),或者将操作所播放音效的实际能耗作为声级的基础。 如果产生的声音在阈值范围之内,您的代理将感知到该实体。

  如果您想要考虑障碍,则可以再一次筛选这一列表:对环境执行光线追踪,了解是否有东西阻挡声音。 由于很少有材料是完全隔音的,因此您需要以更具创造性的方式从列表中删除实体。

  其他感官

  为代理提供视觉和听觉所需的基本功能可以很轻松地应用到模拟其他感官上。 这里有一个其他潜在感觉的列表,如果设计需要,您可以添加到游戏中:

味觉。使命召唤 4*等最近推出的游戏中添加了让智能代理按照嗅觉跟踪玩家的概念。 为游戏添加气味相对简单: 为游戏中的每个实体提供一个不同的气味编号和强度。 气味强度决定着两个因素:气味的半径和留下的气味线索的大小。 活跃的玩家实体通常会出于一些原因记录其最后的几个位置(本文稍后将在线索中介绍更多信息)。 其中一个原因是帮助有气味的实体。 随着玩家实体更新线索,气味的强度随着线索的”淡化“而逐步减小。 当更新有气味的代理时,它需要像检查声音那样检查气味:检查半径和墙面。 有了气味,成功的因素便立足于气味的强度和代理的嗅觉,这些将对照实体和实体的线索进行检查。

雷达。有些游戏为玩家提供个人雷达,这使得感知变得更简单。 只需一个简单的半径检查即可。 随后人工智能便可以验证结果,了解其影响。 对于团队游戏,雷达本身可以变得更加有趣。 为了汇总基于团队的人工智能,每个团队需要制定一个包含雷达发现的实体的雷达列表。 然后团队的每个成员便可以只针对已知实体的列表执行半径检查,以确定团队是否应该做出响应。 团队可以使用雷达设备(如深入敌后: 雷神战争*游戏中),按照添加“看到”的任何内容的每个团队编号添加至列表中。 这一行为可帮助实体作为一个部队工作,因为每个实体都会将其看到的内容告知其他实体。

触摸。这种感觉比较轻而易举,因为游戏引擎的碰撞系统会自动涵盖它。 您只需确保智能代理能够响应损坏和碰撞事件即可。

味觉。我不确定这种感觉如何运作。 它可能是气味的一种属性,但需要代理主动“品尝”其发现的东西。

  能够感知周围世界当然很好,但代理应该感知到什么呢? 您需要指定并能够确定通过代理的设置进行观察的事物。 当您认出看到的事物,您的代理可以根据管理实体的规则对其作出响应。

  临时实体

  临时实体有时也称为粒子、贴标或特效,是游戏世界中的视觉效果。 它们与实体类似,因为一个总体类结构定义所有潜在临时实体,但它们又不同于实体,因为它们不思考和响应游戏世界中的实体,也不与实体互动或相互响应或互动。 他们唯一的目的就是为了美观,在一段时间内为游戏世界提供额外细节,然后就会死去。 临时实体用于子弹轨迹、烟雾、火花、血喷甚至脚印等事物。

  临时实体的性质意味着处理很少且无碰撞检测(超出非常简单的世界碰撞)。 问题在于,有些临时实体为玩家提供了有关已发生事件的视觉线索(弹孔和烧伤痕迹表示最近发生过战斗,雪地上的脚印可帮助找到潜在目标),那么为何您的智能代理也不能使用它呢?

  此问题有两种解决方法: 您既可以通过增强临时实体系统来支持光线追踪(会破坏一个临时实体系统的整点),也可以在临时实体的一般临近区域投下一个空实体。 这一空白实体没有思考能力,也没有与其相关的图像,但您的代理能够检测到它,并且临时实体拥有为代理提供“英特尔”的相关信息。 因此,当一滩散血效果掉落在地上时,您可以在那里投下一个无形实体,让您的代理知道有不寻常的事情发生了。 对于脚印的问题,您已经有掩护它的线索了。

  掩护

  在很多射击游戏中,如果您的代理可以聪明地躲在掩护后面,而不是只是站在空地处等着被击中,那真是太好了。 这个问题比我之前介绍的其他问题更专业一些。 您的代理如何确定是否有可以躲藏的可用掩护?



  Penny Arcade* 讽刺了敌人人工智能和掩护物的问题。

  实际上,这一窘境是两个问题: 如何从实际几何结构方面确定掩护物,以及如何从实际实体方面确定掩护物(如上述的漫画所示)。 如要确定一个实体是否能够阻挡攻击,您可以简单地验证一下,比较一下选中的掩护物的边框尺寸。 然后,验证一下您的实体是否能够躲在它后面。 验证方法是,从射击者和掩护物的不同位置创建一束光。 利用这束光来确定(从射击者)穿过掩护物的点是否不会造成影响,然后将该区域标记为代理的下一个目标。



  在本示例中,代理确定了绿星是能够避开伤害的安全点。

  AI 导航

  目前为止,我已经聊了许多人工智能如何做决定及其如何知道将会发生什么(以便做出更好的决定)。 现在,我们来了解一下人工智能如何执行这些决定。 接下来是要确定如何从 A 点到 B 点。您可以使用多种方法,具体取决于游戏的性质和性能需求的级别。

  碰撞和转弯

碰撞和转弯是产生实体运动最基本的方式之一。 下面介绍一下它的工作原理:

在目标方向移动。

  如果撞到一面墙,转向让你距离目标最近的方向。 如果没有明显更好的选择,请随机选择一个。

  这种方法对于简单的游戏非常有效。 数不胜数的游戏使用这种方法来控制怪兽如何追赶玩家。 碰撞和转弯导致实体在追赶玩家时卡在凹陷的墙或角落中,因此,对于有僵尸或没有这种地貌的游戏,这种方法非常理想。

  但是,如果游戏要求代理更机敏,您可以对简单的碰撞和转弯进行更详细地介绍,为您的代理赋予一些记忆。 如果代理能够记住他们到过哪里,则可对如何转弯做出更有意义的决定。 转完所有弯后,代理将可原路返回,做不同的决定。 因此,您的代理能够系统搜索一个目标的路线。 下面介绍一下它的工作原理:

向目标移动。

遇到叉路时做选择。

发现死路时,原路返回到上一选择,再做其他选择。

探索全部可行路线后,放弃。

  这种方法在处理方面不会耗费大量资源,这表示,您支持大量代理也不会降低游戏速度。 这种方法还非常适合处理多线程。 这种方法的缺点是会浪费大量空间,因为每位代理都可能会追踪包括全部可行路线在内的整个地图。

  幸运的是,让代理在共享内存中记录路线,将可避免这一浪费。 但是,可能会产生线程冲突的问题;因此需要将实体路线保存在一个所有代理都能够在移动时向其发送请求,在发现新路线时向其发送更新的单独模块中。 然后,路线地图模块还需要能够解析发现的路线,以避免出现冲突。

  路线查找

  通过碰撞和转弯生成地图是适应不断变化的地图的好方法。 在策略游戏中,玩家不能坐等设备来查找他们的方位。 而且,这些路线图可能会变得非常庞大,这样,在其中搜寻正确的路线将会成为瓶颈。 查找救援路线。

  路线查找问题在游戏开发中基本上已经解决。 像最初的星际争霸 (Starcraft)* (美国暴雪娱乐公司 (Blizzard Entertainment*))一样老的游戏都可以处理大量游戏实体,在大型的复杂地图中找到道路。

  查找路线的核心算法是 'A*' (读为 [?; stɑ?]),可用于查找图表(在本案例中为地图)上任意两点间的最佳路线。 进行简单的在线查找即可发现包含 F、G 和 H 等描述性术语的 clean 算法。 请允许我更清楚地解释一下。

  首先,必须建立两个列表:一个包含尚未核实的节点的列表(未核实),一个包含已核实的节点的列表(已核实)。 每个列表包含一个位置节点、与目标之间的预估距离及其母节点(确保其位于列表中的节点)的参数。 列表最初为空。

  接下来,将起点添加到未核实列表中,无母节点。 然后,输入算法:

从列表中选择外观最佳的节点。

如果该节点是目标,则操作即可完成。

如果该节点不是目标,则需要将其添加至已核实列表。

对于与该节点相邻的每个节点:

  ·如果节点无法行走,则忽略它。
  ·如果节点已在列表中(无论是已核实或未核实),则忽略它。
  ·接下来,将其添加到未核实列表中,将该节点设置为母节点,并预估其到目标的距离(粗略的距离检查即可)。

  实体到达目标图块后,通过追踪不包含母节点的母节点(起始节点)即可构建路线。 这可为实体提供最佳路线,以便其进行查找。 由于该流程仅当代理收到命令或自行决定运动时才会发生,所以它能够从多线程处理获得巨大益处。 代理可以发送路线线程请求,当系统发现该路线时便会向代理提供,而不会影响人工智能的性能。 大多数情况下,系统可以快速获取结果;但是如果有大量路线请求负载,代理便只能空等,或向适合的方向行进(它可能可以使用碰撞和转弯的方法)。 在极大型的地图中,系统可以划分为多个区域,区域间的所有可行路线(或停留点)均可提前进行计算。 在这种情况下,查找路线的人仅需查找最佳路线即可,因而能够快速获得结果。 路线地图仅需关注地图上的变化即可,如当玩家建造了一面墙,仅需根据需要重新运行路线检查即可。 算法使用单独的线程运算,因此可轻松调整,而不会影响游戏中其他部分的性能。

  在路线查找子系统中,多线程处理还可提高系统的性能。 它非常适合实时策略 (RTS) 游戏,或包含大量实体且每个实体都在寻找不同路线的系统。 可同时在不同线程内查找到多条路线。 当然,系统需要记录发现的路线。 同一条路线无需多次发现。

  代码示例

  以下展示了一个仅在 C 语言中部署的 A* 示例。简便起见,我在示例中并未考虑支持函数,因为它们需要针对不同的部署风格进行定制。 本示例基于一个简单的 tile 网格,其中每个 tile 都可以进一步处理,也可不处理。 这仅允许移动到相邻 tile,但是,如果进行微小的改动,便能够允许作对角移动,或者六角形游戏布局。

/*Get Path will return -1 on failure or a number on distance to path

if a path is found, the array pointed to by path will be set with the path in Points*/

int GetPath(int sx,int sy,int gx,int gy,int team,Point *path,int pathlen)

{

int u,i,p;

memset(&Checked,0,sizeof(Checked));

memset(&Unchecked,0,sizeof(Unchecked));

Unchecked[0].s.x = sx;

Unchecked[0].s.y = sy;

Unchecked[0].d = abs(sx - gx) + abs(sy - gy);

Unchecked[0].p.x = -1;

Unchecked[0].p.y = -1;

Unchecked[0].used = 1;

Unchecked[0].steps = 0;

复制代码

  上述代码段可处理已验证和未验证列表的初始化,并将起始节点放入未验证列表。 借助此代码集,算法的其他部分可在循环中运行。

do

{

u = GetBestUnchecked();

/*add */

AddtoList(Checked,Unchecked[u]);

if((Unchecked[u].s.x == gx)&&(Unchecked[u].s.y == gy))

{

break;

}

复制代码

  上述代码段展示了未验证列表中距离目标最近的节点。GetBestUnchecked()可用于验证每个节点与目标之间的预估距离。 如果该 tile 是目标,则循环停止,流程完成。

  下文展示了距离的算法:获取 X 和 Y 方向上与目标之间的预估距离,并将其相加。 一开始,您可能会想使用勾股定理 (a^2 + b^2 = c^2 ),但是完全没必要。 您只需要相对距离,而非确切距离。 处理器处理加减运算的速度比处理乘运算的速度快许多倍,而处理处理乘运算的速度比处理除运算的速度快许多倍。 由于该代码段在一帧中将会处理许多次,所以优化是关键。

/*tile to the left*/

if((Unchecked[u].s.x - 1) >= 0)/*first, make sure we're on the map*/

{

if((IsInList(Unchecked,Unchecked[u].s.x - 1,Unchecked[u].s.y,NULL) == 0)&&(IsInList(Checked,Unchecked[u].s.x - 1,Unchecked[u].s.y,NULL) == 0))

/*make sure we don't repeat a search*/

{

if(TileValid(Unchecked[u].s.x - 1,Unchecked[u].s.y,team))

NewtoList(Unchecked,Unchecked[u].s.x - 1,Unchecked[u].s.y, Unchecked[u].s.x, Unchecked[u].s.y, abs((Unchecked[u].s.x - 1) - gx) + abs(Unchecked[u].s.y - gy), Unchecked[u].steps + 1);

}

}

复制代码

  在上述代码段中,该函数在当前节点的左侧处理 tile。 如果它未添加到已验证或未验证列表中,系统将会尝试将其添加至列表。 TileValid() 是另一个需要定制以满足游戏需求的函数。 如果它通过 TileValid() 验证,将会调用 NewToList(),这将会向未验证列表中添加一个新 tile。 以下三个代码段执行相同的流程,但是指称不同的方向:右、上和下。

/*tile to the right*/

if((Unchecked[u].s.x + 1) < WIDTH)/*first, make sure we're on the map*/

{

if((IsInList(Unchecked,Unchecked[u].s.x + 1,Unchecked[u].s.y,NULL) == 0)&&(IsInList(Checked,Unchecked[u].s.x + 1,Unchecked[u].s.y,NULL) == 0))

/*make sure we don't repeat a search*/

{

if(TileValid(Unchecked[u].s.x + 1,Unchecked[u].s.y,team))

NewtoList(Unchecked,Unchecked[u].s.x + 1,Unchecked[u].s.y, Unchecked[u].s.x, Unchecked[u].s.y, abs((Unchecked[u].s.x + 1) - gx) + abs(Unchecked[u].s.y - gy), Unchecked[u].steps + 1);

}

}

/*tile below*/

if((Unchecked[u].s.y + 1) < HEIGHT)/*first, make sure we're on the map*/

{

if((IsInList(Unchecked,Unchecked[u].s.x ,Unchecked[u].s.y + 1,NULL) == 0)&&(IsInList(Checked,Unchecked[u].s.x,Unchecked[u].s.y + 1,NULL) == 0))

/*make sure we don't repeat a search*/

{

if(TileValid(Unchecked[u].s.x,Unchecked[u].s.y + 1,team))

NewtoList(Unchecked,Unchecked[u].s.x,Unchecked[u].s.y + 1, Unchecked[u].s.x, Unchecked[u].s.y, abs(Unchecked[u].s.x - gx) + abs((Unchecked[u].s.y + 1) - gy), Unchecked[u].steps + 1);

}

}

/*tile above*/

if((Unchecked[u].s.y - 1) >= 0)/*first, make sure we're on the map*/

{

if((IsInList(Unchecked,Unchecked[u].s.x ,Unchecked[u].s.y - 1,NULL) == 0)&&(IsInList(Checked,Unchecked[u].s.x,Unchecked[u].s.y - 1,NULL) == 0))

/*make sure we don't repeat a search*/

{

if(TileValid(Unchecked[u].s.x,Unchecked[u].s.y - 1,team))

NewtoList(Unchecked,Unchecked[u].s.x,Unchecked[u].s.y - 1, Unchecked[u].s.x, Unchecked[u].s.y, abs(Unchecked[u].s.x - gx) + abs((Unchecked[u].s.y - 1) - gy), Unchecked[u].steps + 1);

}

}

memset(&Unchecked[u],0,sizeof(PNode));

复制代码

  该迭代中需要做的最后一件事情是将未验证列表从当前代码中删除。 不再需要该 tile。

}

while(1);

复制代码

  最后一段代码可通过从目标原路返回来构建路线。 一定能够找到返回起始位置的路线,因为路线中的每个代码都会记录将其放入列表中的代码。 然后,返回最终路线(通过参数)。 以下函数可返回新路线的长度。

IsInList(Checked,Unchecked[u].s.x,Unchecked[u].s.y,&u);

p = Checked[u].steps;

if(path != NULL)

{

for(i = (p - 1);i >= 0;i--)

{

path[i].x = Checked[u].s.x;

path[i].y = Checked[u].s.y;

IsInList(Checked,Checked[u].p.x,Checked[u].p.y,&u);

}

}

return p;

}

复制代码

  总结

  智能代理需要观察其周围的世界。 可以使用简单的范围检查和光纤追踪使根据视觉和听觉所做的观察快速成形,帮助代理在游戏过程中以更贴近人类思维的方式做决定。 确定目标后,代理需要寻找路线,去往他们想去的地方。 碰撞和转弯等快速方式适用于短期任务和简单地图,而更复杂的游戏需要分析地图来查找最佳路线。 您可以对这些方法进行优化,以充分利用多线程部署,确保游戏流畅运行,即使需要处理大量实体和复杂地图也是如此。

战术和战略人工智能 (AI)

  上次谈到游戏主角(智能代理,简称 IA)时,他们已经能够观察周围情况并能够判断前进方向。在本文中,我将向大家介绍如何提高代理的智能级别。代理现已能够处理即时情况。现在,大家正在努力实现人工智能。人工智能具有丰富功能,能够处理各种工作。

  战术人工智能

  战术人工智能的作用是协调游戏中智能代理组的工作。这种人工智能的实施对许多类型的游戏都至关重要。战术第一人称射击 (FPS) 游戏中的小队以及实时战略游戏中的单元组都使用战术方法。小组更加高效,因为组员能够相互支持,作为一个整体开展行动,一起获取和分享信息。

  战术人工智能的概念以小组动力为基础,需要游戏跟踪不同的实体小组。每个小组需要与单个成员分开进行更新。您需要使用专用的更新模块实施更新,该模块能够跟踪不同的小组及其目标和组成。然而,这种方法需要为引擎开发一个单独的系统,因此我更喜好使用组长方法 (group captain method)。

  您可为单个小组分配空军上校的角色。小组中的每个其他成员都需要听从组长指挥,根据组长的命令采取相应行动。组长全面负责实施整个小组的战术人工智能计算。

  小组移动: 路径查找

  实体移动是一个实施区域,可通过小组动力进行改进。智能代理用作一个单元可提升移动的效率和逼真度。

  路径查找较为耗时,即使使用预计算的路径图和多线程人工智能进行加速也无效。小组动力可大幅减轻路径查找系统的压力。

  当单元小组获得了行动目标(通过玩家或人工智能指令),最接近目标的单元被设置为组长,所有其他成员都需要跟随组长。当组长被替换时,它需要查询路径系统。借助路径信息,组长可以达到目标。小组中的所有其他单元只需要跟随组长,无论组长要去哪里。

  小组移动:阵型

  由于小组作为一个集体采取行动,因此您能够成功减轻路径系统的负载。遗憾的是,各单元的行动方式较为松散,缺乏组织性。输入阵型。借助阵型,小组能够以规则的图案开展行动,如方阵(历史模拟)或三角形(Codemaster《霸王(Overlord*)》中的士兵开展行动的方式,如图 1 所示)。



图 1. 在《霸王》中,士兵(红色着装者)在听到玩家(身披盔甲者)的命令之后会以编队形式集体行动。

  编队的设置非常简单,而且是对组长概念的延伸。在编队中,每个成员都有一个不可或缺的特定角色。编队组建完成后,每个成员都有特定站位,就像单个成员被指定为组长一样。编队中每个成员的站位都需要与其他成员保持相对距离。

  让我们以《霸王》中的士兵为例。他们以金字塔编队开展行动。在图 2 中,组长“C”只需按照路径行动。成员 1 将在目标成员“C”的后方偏左位置以设定速度行进,成员 2 需与成员 1 保持一致。成员 3 完全以成员 1 而非组长为行动导向。小组中的每位成员都需要以这种编队方式开展行动。



图 2. 三角形行动编队设置

  小组战术

  战术不仅仅指以编队形式行进,而且注重团队并肩作战。组长负责团队的规划和协调工作。毕竟,保护小组成员的生命是指挥官的职责所在。

  小组战术的实施需使用以往文章探讨的系统,如基于规则的系统或有限状态机 (FSM)。下面列举一些有关典型小组行动的示例(见图 3):

治疗支持。有些游戏具有医疗兵或牧师等治疗支持角色,例如,游戏中的医疗兵需要了解小组成员的健康水平。组长可根据相关信息安排战斗。例如,组长可命令医疗兵守护在可能受到火力攻击的组员附近。

侦察。在《深入敌后:雷神战争 (Enemy Territory: Quake Wars)》*等游戏中,相关角色可为其他组员提供侦察服务。在这款游戏中,侦察兵可以部署雷达以提供有关敌军行动的信息。即使没有雷达,任何被战斗人员发现的敌人将被添加到整个团队中的小组雷达。如欲接近未覆盖的区域,可派遣人员潜入未知区域侦察敌方阵地。经过乔装打扮的任何侦察兵可轻松完成这一任务。

掩护火力。当某区域受到周全防御时,支持人员可以提供掩护火力,集中攻击敌人防御部队,尽可能延长与他们的交战时间,以便到达攻击目标。

牺牲。当敌方攻击火力异常密集且人员牺牲不可避免,应考虑组织敢死队。负责关键任务的小组成员(如某些情况下的工兵)需要受到保护,具体方式包括优先攻击以己方工兵为打击目标的敌方人员,以及参与火线狙击,保护工兵的生命安全。



图 3. 在 Id Software* 和 Splash Damage, Ltd.* 开发的《深入敌后:雷神战争》中,小组动力包括五种不同角色的士兵。

  另一个可帮助小组的分析级别是针对每位小组成员能力的自我分析。组长需要了解小组在哪些情况下能够有效作战,小组何时具备优势以及何时撤退。

  例如,Blizzard 的《星际争霸 (Starcraft)》*等战略游戏包含飞行部队和地面部队。并非每个地面部队都能攻击飞行部队。每个小组都需要了解自身是否具备这一攻击能力。如果小组不具备任何可攻击飞行部队的部队,那么当飞行部队来袭时最好逃跑。即使能够攻击飞行部队的部队数量不多,只要支持部队能够为攻击飞行部队的部队提供治疗服务或支援,那么最好与飞行部队顽强对抗。

  实体能力的多样性及具备实体能力的部队数量可用于衡量小组在不同情况下的战斗力。考虑这些因素能够大幅增强战斗力。

  战略人工智能

  至此,我介绍了实体和实体小组可如何应对艰难的作战环境。现在,我将介绍人工智能的更大意义。战略人工智能是更高级别的人工智能,可用于指挥整个军队和制定指导战略。

  战略人工智能最常用于实时战略 (RTS) 游戏,但正日益频繁地用于战术 FPS 游戏。玩家控制的指挥官可以使用自身的系统,或设置为空实体系统,即没有场地或图形,但会进行更新并具有思考能力。

  指挥官将由等级规则系统和 FSM 指导,它们用于管理多种元素,如资源收集、研究技术树、构建军队等。在多数情况下,游戏元素的这种基本维护不需要太多实际思考能力。而与其他玩家进行互动则需要智能。

  战略人工智能的基本要素可用于支持这类互动(或战斗)。指挥官需要了解游戏地图,以找到玩家,识别关键点(如障碍),构建防御系统,并分析其他玩家的防御策略。具体如何执行并不明确,但决策地图能够发挥重要作用。

  决策地图

  决策地图是二维阵列,类似于游戏地图。阵列中的每个单元对应着游戏中的一个区域,并具有关于该区域的重要信息。这些地图可用于帮助您的战略人工智能针对整个游戏制定有效决策。

  资源地图

  资源地图包含战略游戏中资源的位置信息。了解资源集中在地图的什么位置可影响指挥官的许多决策,例如在哪部署扩充或卫星基地(指挥官基地附近的资源),敌方可能在哪部署其扩充(他们基地附近的资源)以及可能需要争夺的阵地(中间资源)。

  计算潜在的可用资源还可影响支持哪些部队以及如何部署军队。如果资源缺乏,那么指挥官在为每个部队安排任务时需要更谨慎,因为补充兵员可能较少。如果资源充裕,那么指挥官便可实施积极作战战略,动员大量兵员或组建强大的作战部队。

  进攻地图

  这些地图包含有关指挥官目标的信息,例如敌军基地位置、地图目标(炸毁、保护、攻击等)位置、指挥官军队的要素(主要基地、英雄部队等)。掌握这些信息可帮助指挥官合理部署军队。需要保护的据点应该被防御工事环绕,并安排小分队始终驻守在这些据点附近。找到攻击目标后便可对防御工事进行测试。必须通过分析目标周围的防御工事找到最佳的攻破策略。这是军事游戏冲突地图的基础。

  冲突地图

  冲突地图(见图 4)的使用和更新频率远高于前述地图。冲突地图可在整个关卡中跟踪战斗的发生场所。无论何时与敌军战斗,士兵都需要使用关键信息及时更新冲突地图:

冲突类型。部队和/或建筑物

部队能力。攻击地面和/或空中力量

数量。遭遇的敌军数量

兵力。相关区域的破坏潜力

  通过分析这些信息,可确定以下情况:

当敌人发动攻击时,人工智能将能判定部署的防御措施是否有效,防御措施是得到启用还是被忽略,以及冲突是否发生在防御目标附近。然后,人工智能可以适当改变防御工事的布局和结构。

在攻击敌人(最好有侦察兵提供协助)时,快速找到敌军防御工事的弱点。如果路径有利于避免冲突或最大限度减少冲突,您便可以实施最佳的军队部署战略。

对抗措施是否适当取决于敌军军事能力的组成。因为多数战略游戏试图在各部队之间保持某种平衡,所以电脑将能够确定突破不同据点防御措施所需的部队数量和类型。



图 4. 某地形上的冲突地图示例。红色越黑,遭遇的冲突越多。

  构建和应用地图

  我以前说过,这些地图由指挥官的部队构建。它们属于规则的一部分,旨在引导人工智能尽快派遣侦察兵探秘敌军阵地,以开始构建地图。卓越的人工智能应该定期确保这些地图处于最新状态。在游戏开始时,只有少数部队具有这些地图,因此游戏引擎更新比较容易。当游戏正在激烈进行时,大量部队同时提供信息,这可能会影响游戏的运行性能。

  确保决策地图快速得到维护并不太难,通过将决策地图系统集成到其线程中便可做到。事实上,人工智能控制的每位玩家都应该具有自己的线程,以处理自己的一套决策地图。如果所有的实体都分解为多个线程,那么性能便会得到真正提升。决策地图线程只需要处理并行化实体更新消息中的请求。

  总结

  智能系统采用的最基本形式是基于规则的系统。该系统需充分利用人工智能特性,因为实际的智能性较低。一组预设行为用于确定游戏实体的行为。对于各种行为,总体结果可以是不明显的行为系统。

  游戏世界的智能代理开始形成。您能够借助其基本能力开展侦察和行动,并增强决策和行为的有效性。您的智能代理现在能够在游戏扮演更主动的角色,而不是仅仅被动应对局势变化。您能够为玩家创建更聪明和难以对付对手,反过来,厉害的玩家能够取得出色的成绩。

  本系列到此结束。下篇文章将重点介绍将多线程应用于人工智能。您甚至将获得一些实用高效的算法来运行人工智能,随着应用于更多的实体,它们将不可避免地变得日益复杂。如果希望您的系统能够满足增长的需求,您需要利用多核处理器。下篇文章将介绍通过简单改动代码,获取多线程优势。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: