UDN
Search public documentation:
NavMeshConstraintsAndGoalEvaluatorsCH
English Translation
日本語訳
한국어
Interested in the Unreal Engine?
Visit the Unreal Technology site.
Looking for jobs and company info?
Check out the Epic games site.
Questions about support via UDN?
Contact the UDN Staff
日本語訳
한국어
Interested in the Unreal Engine?
Visit the Unreal Technology site.
Looking for jobs and company info?
Check out the Epic games site.
Questions about support via UDN?
Contact the UDN Staff
导航网格物体路径约束及目标点求值器
概述
本文档对路径约束及路径目标点求值程序的目的及应用进行了概述,因为它们和寻路及一般的路径遍历相关。
为什么?
这些模块化的自定义的约束的出现允许 AI 程序员只需要很少的代码修改便可以运行特定的路径搜索来满足游戏的特定需要。过去,如果您想执行类似于 查找远离实体的从 A->B 的路径 的操作,您必须在 native 代码中的路径消耗函数中添加这种特殊的情况,并且对于每一种新的情况都需要执行这个操作。很快便会发现这是不实用的。对于您需要的用于进行特定路径搜索的每个自定义考虑项(约束)的不同组合,都要针对每个新的搜索添加新的代码。 而我们的方法是把关系的对象打包到称为 PathConstraints 的自包含对象中,这里可以添加在寻路过程中考虑的所有信息。所以,如果您正在尝试查找到您的目的地的最短路径,那么您可以简单地添加一个 Path_TowardGoal 约束,这样您将会获得 AI 程序员所熟知的经典的线性的 A* 启发式搜索。然而,如果您想进行更加复杂的操作,比如查找避开触发器从 A -> B 的最短路径,您将需要简单地添加 Path_TowardGoal 约束和一个(假想的) Path_AvoidFire 约束。这是很容易完成,并且可以通过脚本访问它们,所以通过拼凑自定义的、一次性的路径搜索来满足您的精确地特定情况是很容易的。 然而,约束只是成功的一半。您也需要具备指出路径搜索的结束条件并在遍历路径的过程中标记数据。这便是路径目标点求值器设计的目的所在。 它们既指出了搜索何时完成(比如,当我们找到一个有效的目标节点时),也处理了计算得出的数据的标记和存储。比如,在战争机器中,当搜索掩体时,则会使用一个 掩体目标点求值器 。 这个自定义的目标点求值器将会继续搜索直到找到满足条件的掩体节点为止,它将会跟踪到现在为止找到的掩体节点,并沿着路线记录它们。最基本的(经常使用的)路径目标求值程序是 Goal_AtActor ,当找到了包含着搜索的目标点的导航网格物体多边形时,它将会简单地停止搜索。这是您在查找从 A->B 之间的最短路径的目标求值器。 约束和目标求值器存储在导航句柄上的两个列表上。路径约束
正如上面所提到的,路径约束既可以修改存储的实际距离 (g),也可以修改启发式距离 (h)。最近,路径约束也可以在特定的节点上返回 false,这意味着这个节点是完全不适合的并且根本不应该将其添加到打开列表。 可以应用路径约束的情况:
- 朝向目标点的遍历(比如,通过首先尝试朝向目标点的节点来优化搜索)。
- 通过或条件性地限制不能遍历的区域来限制遍历(比如,触发器、熔岩、仅用户优化的门)。
- 远离不需要的对象来调整遍历(比如,敌人玩家)。
- 收集/存储 数据时(如果前一个约束返回 false,那么您的约束可能不会被调用)。
路径目标点求值器
路径目标点求值器稍微有点复杂,因为它们处理了大多数的节本寻路函数,比如决定开始节点和结束节点,以及一旦由于任何原因导致搜索终止,那么那个节点来调用‘目标节点’。 目标点求值器建立了搜索、决定了什么时候完成、并且当找到目标点时将会把找到的路径保存到导航句柄中。 注意: 列表中的 第一个 路径目标点求值器有特殊的意义。它作为主要的求值器,因此它将控制搜索的初始化(比如 seedworkingset(搜索工作的节点集合)、initializesearch(初始化搜索)) 这里是典型的路径目标点求值器的所做的事:
- InitializeSearch() - 这个函数在路径搜索的开始阶段进行调用。这允许目标求值器设置它进行搜索过程所需要的任何东西。默认的功能是查找到包含 SearchStart 的多边形,并设置它为 AnchorPoly 。
- SeedWorkingSet() - 它是家下来调用的函数。 这个函数负责向打开列表填充一个或多个多边形来供其进行搜索。 默认的功能是简单地把锚点多边形添加到工作集中。
- EvaluateGoal() - 当最好的节点离开工作集后调用这个函数… 这个函数将会在每个节点上依次调用称为 EvaluateGoal() 的整个路径目标求值器列表。 这使得列表中的每个目标点求值器都有机会标记多边形以及当找到适当的节点时调用停止函数来终止搜索。
- DetermineFinalGoal() - 只要路径完成,便会调用这个函数。(或者因为找到了一个目标点或者因为已经搜索过了要测试的所有的节点)这允许目标点求值器来执行最终的计算并决定实际的最佳目标点是什么(如果存在)。这里函数的默认行为是判断是否找到了目标点,但是在更加复杂的求值器比如 Goal_AtCover 中,最终的结果由到目前为止所访问的多边形来决定最适合的目标点是什么。
- SaveResultingPath() - 是求值器中最后调用的函数。在几乎所有的目标点求值器上,这个函数简单地反向遍历前面的节点链来按照从开始节点到目标点的顺序来保存路径。 但是,这允许自定义的求值器来在这里执行一些不同的操作。比如, Goal_ClosestActorInList (按照从目标点到开始点进行寻路)是按照顺序的顺序来存储路径的,因为它反转到了开始点(请参照以下获得关于这个求值器的更多信息)。
- NotifyExceededMaxPathVisits() - 是在例外情况下调用的一个函数。当访问的多边形的数量超过 navigation handle(导航句柄)上的 MaxPathVisits 参数时,将会调用这个函数。在大多数情况下,这意味着失败(比如,在最大的样本范围内没有找到目标点)。但是有时这仅意味着搜索完成(比如 Goal_Null 仅在搜索完所有节点或者碰到最大的访问范围时才停止搜索..这对于找到一个区域内的最佳节点是有用的)。
- bUseORforEvaluateGoal (在 UNavigationHandle 上) - 默认情况下,为了判断搜索的结束与否, 所有 的目标点求值器都会从 EvaluateGoal() 中返回 true。 这个返回值可以通过使用 navigation handle(导航句柄)上的 bUseORforEvaluateGoal 来进行修改。(当返回值为 true 时,如果从目标求值器中的任何 EvaluateGoal() 中返回 true,那么搜索将会终止)。
- bAlwaysCallEvaluateGoal (在 GoalEvaluator 上) - 当特定的目标点求值器的这项为 true 时,那么即使目标点求值器已经判定了当前的节点是否是最终目标点,仍然会调用目标求值器的 EvaluateGoal() 函数。 这对于需要针对每个路径迭代存储信息或计算某些数据的目标点求值器是有用的。
Constraint(约束)/GoalEval(目标点求值器)池
为了防止不断地新建不必要的路径约束和目标点求值器,可以根据需要新建它们并缓存它们。 这允许在不需要新建及垃圾回收大量约束的情况下重新使用缓存的约束及目标点求值器。 为了达到这个目的,您应该永远都不要直接地新建 PathConstraint 或 GoalEvaluator。反之,您应该在 NavigationHandle 上调用 CreatePathConstraint() 或 CreatePathGoalEvaluator() 函数。在还没有缓存一个约束或者检索到一个缓存的副本,那么它将新建一个该约束的副本。 作为缓存过程的一部分,当从句柄中清除一个约束时,将会调用 Recycle() 事件。在这个函数中,所有的状态都将会被清除并重置为默认值。 当重写 PathConstraint 和 GoalEvaluator 时,重写这个函数并清除任何可能成为您的衍生类一部分的任何新的状态是很重要的,以便您不会使用来自循环使用的约束的旧数据。
示例使用情况
在 约束/求值器 上实现一个静态函数是很方便的,您仅需要调用它将该约束或求值器添加到句柄列表即可。这里是 Path_TowardGoal 约束的一个这样的静态函数实例:
static function bool TowardGoal(NavigationHandle NavHandle, Actor Goal) { local NavMeshPath_Toward Con; if (NavHandle != None && Goal != None) { Con = NavMeshPath_Toward(NavHandle.CreatePathConstraint(default.class)); if (Con != None) { Con.GoalActor = Goal; NavHandle.AddPathConstraint( Con ); return TRUE; } } return FALSE; }