开放世界玩家载具驾驶 P7:局部避让与即时风险——车辆如何在不改变路线的情况下处理眼前冲突?

本文属于「开放世界玩家载具驾驶」系列第七篇,承接 P5 的导航路线和 P6 的驾驶策略。P5 维护车辆应当通往哪里,P6 描述同一条通路上不同驾驶者如何取舍;本篇继续向下追问:当前道路上突然出现行人、车辆、物体或不可通过的边界时,车辆如何在不重建整个目的地的前提下处理眼前冲突?

本文的核心判断是:局部避让不承担第二套导航,也不直接写入车辆控制量;它是一段具有明确输入、几何判断、候选生成、结果评分和恢复出口的短时运行时。它把当前局部空间转换为可消费的方向、速度或等待约束,再交回原有任务和执行链。全局路线仍由 P5 的路线持有层维护,驾驶偏好仍由 P6 的策略层调制,最终控制量与物理接缝留给 P8。

文章依据 GTA5 相关源码阅读笔记整理。公开文本对类名、函数名和项目标识做了匿名化处理;文中会区分源码直接呈现的职责、依据调用关系抽象出的结构,以及后续目标运行时中的迁移设想。局部避让源码材料主要展示了行人移动任务中的几何辅助,但其输入组织、候选搜索、碰撞时间和结果消费方式,对理解车辆驾驶运行时同样有参考价值。涉及玩家近失、道路风险和鸣笛状态的部分,则会明确标记为玩家信息路径,不把观察状态误写成 AI 驾驶控制。

P5、P6、P7 与 P8 的职责边界

上一篇:开放世界玩家载具驾驶 P6:驾驶策略与风险模型——相同路线为什么产生不同驾驶行为?


引言:路线没有改变,眼前空间却已经改变

假设一辆车正在沿导航路线通过城市主干道。路线持有层已经完成目标确认,当前路段、下一处路口和目标方向都有效;驾驶策略也已经给出当前驾驶者的速度偏好、跟车距离和风险权重。此时,一辆停靠车辆突然打开车门,前车在车道中央急刹,行人从路边进入车辆前方,或者道路边缘的动态物体占据了原本可以通过的空间。

从玩家视角看,处理方式似乎只有两种:车辆规避障碍,或暂时减速等待。从运行时角度看,系统至少需要同时回答几件事:

  • 当前对象是否真的位于车辆的行进走廊内;
  • 对象的速度和方向是否会在短时间内造成冲突;
  • 当前路线两侧是否存在可接受的局部方向;
  • 左侧和右侧的候选哪个更接近原目标;
  • 当前风险是否足以要求等待、制动或暂时偏移;
  • 这次偏移结束后,车辆如何回到原有路线;
  • 如果局部处理失败,谁有权请求更高层重规划。

这组问题不能由一个 Avoid = true 的布尔值表达。布尔值只能说明“发生了某种状态”,无法说明冲突对象、预测时间、候选方向、选择依据和恢复条件。局部避让实际维护的是一条短生命周期关系:发现局部冲突,建立候选,选择临时方向,交付给移动任务,并在冲突解除后释放临时影响。

可以先用一条简化链路表示:

路线、局部目标与执行路径

局部避让的价值,不在于替代路线,而在于让路线可以在短时空间冲突中保持连续。


路线与局部冲突

一、局部避让解决空间冲突,路线层维护目的地关系

P5 将目标、路线和局部目标分开。车辆知道最终要去哪里,也知道接下来应当经过哪些道路;但路线并不包含每一帧的动态对象位置。道路图能描述连接关系,路线能描述计划通路,局部避让才需要处理当前几何空间中的临时变化。

三层问题可以按职责区分:

层次 核心问题 主要结果
目标层 车辆最终要到哪里 目标约束
路线层 车辆应当经过哪些道路 路线段、车道和路口上下文
局部层 当前几何上哪些短时动作可行 等待、制动、偏移目标或候选方向

如果前方只是一个短暂占道对象,局部层应当优先处理,避免立即让路线持有层重新搜索整个城市。相反,如果道路结构已经失效,局部层反复左右尝试也不能解决问题,路线持有层才需要获得受阻反馈并决定是否重规划。

这就是 P5 与 P7 的第一条接缝:局部避让可以改变车辆当前如何接近局部目标,但不自动获得修改全局目的地和路线生命周期的权限。

一个常见误区:把“偏离路线”理解成“路线失效”

车辆为了避开一辆临时停靠的车,可能短暂离开路线中心线。这个现象本身不代表全局路线已经失效。局部移动任务可以保存原始路线方向,在障碍解除后将临时分离向量清除,再重新接入原来的路线目标。

若把每一次局部偏移都视为全局路线失败,系统会不断发起异步搜索:车辆避开一个对象,路线被重建;新路线又改变车道,局部避让再次触发;最终车辆表现为路线抖动,无法保持稳定行驶。


二、局部避让承担被任务调用的计算职责,不维护常驻全局状态

源码阅读中最容易出现的误读,是看到一个名为避让的文件或命名空间,就把它理解成拥有所有避让状态的全局系统。当前材料呈现出的结构更接近:移动任务拥有执行生命周期,局部避让模块提供一组几何辅助和短时结果。

本文用 LocalAvoidanceKernel 作为公开别名,表示这组局部避让计算职责;用 MoveToPointTask 表示调用它并消费结果的移动任务。别名不对应源码中的唯一类名,也不意味着真实实现只有一个入口。

从职责上看,LocalAvoidanceKernel 接收:

  • 当前移动实体的位置和速度;
  • 目标方向或当前分离方向;
  • 当前路线段的局部基准;
  • 扫描距离与距离路线的偏差;
  • 可以忽略的实体;
  • 是否允许处理特殊对象;
  • 调用方提供的阈值和开关。

它返回的内容反而很小:

  • 一个局部避让方向或分离向量;
  • 可选的碰撞时间;
  • 可选的碰撞速度或风险反馈。

它不保存全局路线,不决定任务完成,不拥有附近实体列表,也不直接写入刚体控制量。调用方需要决定什么时候运行它、运行频率多高、把返回方向写入哪个阶段状态,以及什么时候停止使用结果。

这种组织方式使局部几何计算可以被不同移动任务复用,同时保留各任务自己的目标、成功条件、失败出口和恢复方式。复用的是计算职责,各类移动行为仍由各自任务编排。


局部障碍资格筛选

三、在局部求解前,需要经过资格筛选

局部避让不能把扫描范围内的所有实体都当作同等障碍。实际运行中附近对象可能包括:已经被忽略的实体、已死亡的行人、正在上车的角色、与调用者处于不同高度的对象、挂接在其他实体上的对象、门、拾取物,以及不参与当前路径服务的装饰实体。

因此,局部避让的输入通常经历两层筛选:

局部求解前的资格筛选

过滤不只是性能优化,它决定了“什么会被系统视为当前风险”。如果把一个不参与移动的门、一个已经在车内的行人或一个高度明显不同的对象送入预测器,几何求解可能得到数学上正确、行为上错误的避让结果。

行人候选

行人通常可以用位置、速度和近似半径表示。候选过滤需要关注:

  • 是否为调用者本身或明确排除的实体;
  • 是否已经死亡,以及当前任务是否允许对尸体避让;
  • 是否已经进入车辆或处于进出车关系中;
  • 是否处于不同高度层或室内外不相交空间;
  • 是否被全局忽略、组关系或任务标记排除;
  • 当前速度是否需要扩大预测半径;
  • 是否存在特殊的奔跑、逃离或临时扩大避让范围状态。

因此,“看到行人”与“把行人作为局部碰撞候选”属于两个不同事件。实体扫描器提供可能对象,局部避让层依据当前任务和能力标记决定哪些对象进入计算。

物体候选

动态物体通常需要从路径服务或动态对象缓存中取得边界顶点与速度。挂接对象、门、拾取物和不参与路径服务的对象可能被排除。对物体使用矩形或四边形边界,而非单一半径,是因为车辆或移动实体需要知道障碍的朝向和边缘位置。

车辆候选

车辆候选与物体候选在几何上都可能表现为带速度的动态边界,但过滤条件和消费者语义不同。车辆通常需要考虑车身边界、当前速度、路径服务参与状态、垂直高度差和扫描距离。车辆避让需要超越中心点距离判断:两个车身中心点距离足够远,边界仍可能相交;中心点接近,也不必然表示实际路径冲突。

过滤参数是谁拥有

障碍过滤还会受到任务开关、重置标志、导航能力和全局调试开关影响。局部避让模块读取这些输入,但不一定拥有它们的生命周期。一个“允许避让火焰”的能力标志来自导航能力信息,并不等于避让模块创建或维护了这项能力。

这条边界对迁移很重要:目标运行时需要一个明确的输入面,局部避让模块不应自行读取所有世界状态。


四、圆形障碍与盒状障碍需要不同的几何模型

不同实体使用不同几何近似,原因在于预测问题本身不同。

圆形模型:适合快速移动的行人与火焰

对于一个可用位置、速度和半径近似的行人,可以把相对运动转化为“两个圆在未来是否接近”。系统需要估计:

  • 当前相对位置;
  • 当前相对速度;
  • 预计接触时间;
  • 为绕过未来位置生成的切线方向。

圆形模型的优势是计算简单,适合在一个移动任务更新周期内反复尝试。它并不要求预测行人的完整动画,也不需要知道行人未来会播放哪段动作。它只需要在当前时间窗口内提供足够安全的局部几何近似。

盒状模型:适合车辆和动态物体

车辆、箱体或路径服务提供的动态对象通常需要保留边界顶点和朝向。盒状模型可以检查射线、局部边缘和相对速度之间的关系,并判断哪一侧边缘更可能阻挡当前方向。

盒状模型也表明,边界数据可能来自局部避让之外的服务。路径服务维护动态物体边界,实体扫描器维护附近对象,局部避让只负责把这些数据转换成当前求解可以使用的候选。

导航网格阻挡属于另一类空间证据

导航网格边界、不可见的 LOS 阻挡边缘或局部不可通行区域,不一定有一个可以被扫描器返回的动态实体。它们通常需要通过导航跟踪器或路径服务进行额外查询。

因此,局部避让的候选来源至少包括:

不同实体使用不同几何模型

不同候选来源最后可以进入同一评分循环,但它们的证据和误差特征并不相同。把所有对象统一成一个半径会丢掉车辆朝向、物体边缘和导航阻挡的意义。


碰撞时间与相对速度

五、碰撞预测关注接触时间与相对速度

如果系统只判断“当前是否相交”,避让通常会发生得太晚。局部运行时更关心时间维度:按照当前相对速度继续运动,多久之后会进入不可接受的空间关系?

典型输出包括:

  • 预计碰撞时间;
  • 相对或接近速度;
  • 当前路径偏差;
  • 障碍位于目标方向的哪一侧;
  • 是否已经进入紧急或不可恢复区间。

时间到碰撞可以作为评分的一部分,但不能单独承担最终决策。一个距离较近但相对速度很低的对象,与距离稍远但高速横穿路径的对象,应该产生不同的避让压力。

为什么速度不能单独决定风险

相同速度下,车辆与行人的碰撞几何不同;相同距离下,横向穿越与同向跟随的时间关系不同;相同预测时间下,左右两侧的道路边界又可能不同。因此局部风险至少由空间形状、相对运动和可用方向共同决定。

碰撞时间输出的权威范围

源码中可以观察到,局部辅助返回的碰撞时间和速度可能沿用上一个被处理对象的值,而非每次都更新为最终最近碰撞的真实值。这样的结果更适合作为“当前避让反馈”或调试提示,不宜被视为整个世界唯一权威的碰撞预测服务。

公开文章应保留这一点:返回值的命名不能替代消费关系。要判断一个时间值能不能当作权威风险指标,必须继续追踪它由谁使用、是否会被下一阶段覆盖,以及它是否只服务于当前转向求解。


六、目标方向只是候选起点,左右切线构成局部搜索

局部避让的初始方向通常来自当前移动任务的目标方向或分离方向。这个方向代表“如果没有局部冲突,车辆应当继续往哪里走”。它承担候选搜索的起点作用,尚未形成最终答案。

当预测到障碍时,系统需要生成新的方向。对于圆形障碍,常见方法是围绕预测位置计算左、右切线;对于盒状障碍或导航阻挡,则可以围绕阻挡边缘生成左、右旋转候选。候选方向之后还要受到导航左右边界、路径容差和任务阶段的限制。

候选生成可以抽象为:

从目标方向进入局部候选搜索

这里的“左”与“右”属于当前候选,不应固化为“遇到障碍永远向右”。系统需要根据目标方向、当前朝向、道路边界、候选距离和预测冲突结果进行比较。

切线没有解时怎么办

如果障碍半径、相对位置和当前安全余量使得切线不存在,系统可能使用经过调参的备用角度,或者降低速度、请求等待。备用角度只能提供一个短时方向,不代表找到了安全通路;下游仍需要继续进行导航边界和执行条件检查。

候选方向可能仍然等于原方向

局部计算返回成功,不一定意味着方向发生了明显改变。候选搜索可能确认原方向仍然是当前评分最优的方向,只是完成了风险检查和相关状态刷新。这个细节能防止调试时出现“函数返回成功但车辆没有转向”的误判。


局部候选评分

七、评分函数决定候选侧向选择,但不拥有驾驶策略

候选方向需要有可比较的评分。从当前追踪到的调用关系看,评分因素大致包括:

  • 候选方向与原始目标方向的夹角;
  • 候选方向与移动实体当前朝向的夹角;
  • 候选距离路线或路径中心的偏差;
  • 预计碰撞时间和接近速度;
  • 当前任务是否处于逃离、快速移动或紧急恢复状态;
  • 导航网格左、右可用角度的限制。

可以用一个抽象表达表示:

候选代价由多项约束共同构成

这里没有复述公开实现的逐项公式,而是依据输入和调用关系归纳职责模型。该模型表明局部避让的评分同时考虑多种因素,并非单一距离排序或固定的“向左优先”常量。

P6 的策略可以影响某些软偏好,例如等待成本、横向移动惩罚或风险权重;但评分循环仍然需要由局部避让层收集几何事实。策略可以让某一候选更受欢迎,却不能把一个已经发生边界相交的候选变成安全候选。

硬边界与软偏好

局部避让中至少存在两类条件:

类型 作用 典型来源
硬边界 排除不可行候选 车身碰撞、导航阻挡、道路边界
软偏好 在可行候选之间排序 偏离距离、等待成本、方向变化倾向

如果把所有条件都塞进一个分数,硬碰撞可能被“目标更近”抵消;如果把所有条件都做成硬拒绝,车辆又会失去可调的驾驶风格。更清晰的做法是先过滤不可行候选,再用软偏好排序剩余候选。


八、移动任务拥有局部避让的调用与消费路径

局部辅助不会自己决定什么时候扫描。当前移动任务通常拥有以下状态:

  • 当前目标位置或目标方向;
  • 当前分离向量;
  • 路径容差;
  • 最大避让时间或距离阈值;
  • 上一次避让结果;
  • 生成分离向量的计时器;
  • 是否允许行人、物体、车辆和导航网格避让;
  • 目标是否已经满足、任务是否完成或被取消。

移动任务在合适的更新阶段构造避让参数,调用局部辅助,再把返回方向写入自己的分离目标或局部目标状态。之后,移动任务继续负责速度混合、朝向变化、目标到达、停止精度和任务结束。

这条调用关系回答了一个关键问题:局部避让结果属于移动任务在某个阶段消费的临时中间结果,车辆任务和物理系统分别保留各自的生命周期与执行职责。

如果把局部辅助提升为全局任务树,它就会开始承担路线、目标、完成和恢复;如果让物理系统直接调用它,又会绕过任务的生命周期。两种做法都会让短时几何判断失去边界。


九、扫描频率和距离阈值决定即时风险的时间尺度

“实时避让”不等于每个系统都每帧扫描所有对象。局部避让通常受到扫描距离、移动速度、路径偏差、任务阶段和计时器约束。

速度越高,前视窗口越重要

相同扫描距离下,高速车辆留给局部处理的时间更短。运行时可以通过前视距离、最大避让时间或候选刷新频率改变反应窗口。这个参数不一定由局部几何模块独占,可能由移动任务或车辆类型提供。

距离路线的偏差会改变对象资格

某些对象避让只有在移动实体已经偏离路径一定距离后才启用;导航网格边缘检查也可能需要动态避让已经启动后才进入。这样的门控属于运行时预算设计,用于避免在正常路线跟随阶段持续求解远处无关边缘。

重置标志可以改变安全余量

紧急恢复、逃跑或任务重置状态可能收紧切线和碰撞 padding,限制可接受的转向角。它们是调用方提供的策略上下文,局部避让根据这些上下文调整几何求解,但不拥有任务状态本身。

采样预算也是运行时语义

开放世界中同时存在大量移动实体。局部避让如果无条件扩大扫描半径、提高所有候选的几何精度,就会把每辆车的短时反应变成全世界实体的全量查询。更合理的做法是先由速度、路线阶段和当前风险决定预算,再在预算内进行分类型求解。

低速接近停止时,系统可以减少远距离预测,优先确认近处边界;高速行驶时,应增加前视距离并优先处理高速横穿对象;进入狭窄路口时,候选数量可能减少,但边界检查需要更严格。预算变化不只是性能开关,它会改变局部结果的时间尺度,因此也必须进入诊断记录。

扫描预算还需要和任务的刷新周期对齐。若扫描每隔数帧运行一次,而移动任务每帧继续消费上一次分离向量,就必须记录结果的有效期;若一个紧急风险在下一次扫描前已经解除,旧方向不能继续无限保留。由此可见,局部避让的稳定性既来自几何公式,也来自调用频率、缓存清理和任务阶段的共同约束。


路线层、局部目标与执行层边界

十、局部避让与导航网格:导航查询提供局部可行性证据

道路路线提供的是车辆希望经过的道路关系,导航网格或空间查询可以帮助判断局部偏移是否仍然处于可行区域。二者不能混成一套数据。

当动态对象造成冲突时,系统可能先生成左右候选,再用导航跟踪器检查候选方向附近是否存在不可通行边缘。如果左侧已经被墙、路缘或导航网格缺口阻挡,候选就需要被限制;如果两侧都不可行,局部避让不应继续无限生成角度,而应把“局部无法解决”交给更高层处理。

为什么不直接用导航网格重算路线

导航网格搜索可能适合重新寻找空间通路,但玩家车辆、道路车辆和不同车型的语义约束不同。车辆宽度、道路车道、路口通行、速度限制和路线持有关系不能因为局部避让使用了导航查询就被抹平。

更合理的关系是:

路线、局部层、导航查询与执行层

导航查询是局部判断的服务,不等于它成为驾驶任务的所有者。


十一、共享几何原则,但保留类型专用解释

P7 的几何原则可以跨实体复用,但同一局部结果仍需由当前载具类型解释。不同载具的运动语义、尺寸约束和可执行范围并不相同;本篇只保留这一接口边界,不展开各车型的控制律。汽车、船舶、飞机和其他载具的具体差异留在 P8 展开。

共享的部分包括:

  • 当前目标方向;
  • 障碍候选;
  • 预测时间;
  • 左右候选;
  • 风险评分;
  • 临时目标或等待请求。

不应直接共享的部分包括:

  • 最终转向角;
  • 轮胎或推进器控制;
  • 车身姿态;
  • 物理恢复;
  • 运动学约束。

这与 P2 中“共享契约,不共享运动语义”的结论一致。P7 可以提供局部意图和约束,P8 再由车型执行器把它转换为相应运动。


玩家风险路径与 AI 局部避让

十二、玩家车辆的即时风险路径不能直接等同于 AI 局部避让

玩家驾驶中的道路风险材料提供了一个容易混淆的例子。玩家信息路径可以记录:闯红灯、驶上路面、逆向行驶、碰撞、近失、道路类型和高速路状态。这些数据可能被统计、音频、警示、人口或派遣系统消费。

它们不因此成为玩家车辆的 AI 避让策略。

AI 车辆局部避让

AI 车辆需要在当前周期决定是否减速、等待、偏移或选择另一侧。局部避让结果进入 AI 任务和执行链。

玩家车辆风险观察

玩家车辆通常由玩家输入直接提供主要运动意图。系统可以观察玩家是否接近碰撞、是否逆行、是否在高速路上行驶,并据此产生提示、统计和世界响应。观察路径不能未经授权覆盖玩家输入。

近失事件与碰撞事件的语义不同

近失可以由高接近速度、短时边界重叠风险或扩展后的物理边界判断得到,但没有实际碰撞。它适合成为事件记录和反馈入口,不应自动写成损伤或已发生碰撞。

这个区分能避免文章把“风险”一词泛化成一个全局开关:风险可能是 AI 的决策输入,也可能是玩家行为的观察结果,还可能是统计与音频系统的事件来源。


局部避让状态生命周期

十三、局部避让状态需要区分处理阶段

局部处理至少需要区分以下阶段:

局部避让状态生命周期

其中任何阶段都可能失败:对象消失、候选被道路边界排除、车辆无法按执行器约束转向、路线任务被取消、实体速度突然改变,或者局部偏移已经超过允许走廊。

在目标运行时中,建议为局部结果附带:

  • 产生时间或有效周期;
  • 目标方向来源;
  • 冲突对象或冲突类型;
  • 结果状态;
  • 是否可以恢复原目标;
  • 是否需要向路线层报告受阻。

如果只保存一个 bAvoiding,系统无法知道当前状态是等待、侧向绕行、恢复还是已经失效。


十四、失败路径:避让没有找到方向时,谁负责下一步

局部避让失败不一定表示整条路线失败。需要区分至少四类情况:

1. 没有合格障碍候选

这可能意味着当前空间安全,也可能意味着扫描器没有提供完整数据。调用方要结合扫描状态和任务上下文判断,不能把空数组直接解释成道路畅通。

2. 候选全部被几何边界排除

左、右方向都被导航边缘、车身边界或空间条件排除时,局部层可以请求等待或报告局部阻塞。它不应自行伪造一个穿过障碍的方向。

3. 候选存在但执行器无法完成

局部几何认为方向可行,不代表车型执行器能够及时转向或制动。执行器拒绝、物理反馈异常或速度无法降低时,需要回传失效状态,不能把几何结果当作已经完成。

4. 局部失败持续超过路线容忍度

当等待、偏移和恢复多次失败,路线持有层才需要判断是否重新请求路径、切换路线模式或结束任务。

这条故障链可以写成:

局部候选失败后的恢复路径

局部层负责提供“当前空间不能继续”的证据,路线层负责决定“是否需要换一条更高层路径”。


十五、恢复过程应当逐步回接原路线

障碍解除后,车辆仍可能处于路线一侧。若直接把方向目标重置为原路线中心,车辆会产生过大的横向修正,甚至再次触发新的避让。

更稳定的恢复方式是分阶段进行:

  1. 确认原路线目标仍然有效;
  2. 清除已经失效的障碍引用;
  3. 保留当前速度和车辆类型限制;
  4. 生成一个逐步靠近路线走廊的局部目标;
  5. 由同一个移动任务重新消费路线方向;
  6. 当偏差回到容忍范围后释放临时分离状态。

恢复过程不应重建整棵任务树。它只需要清理临时局部状态,并让原任务重新获得目标方向的主导权。

为什么恢复属于调用任务

局部避让辅助只能知道它生成了一个方向,未必知道路线是否已经前进、目标是否改变、任务是否完成。调用任务保存这些生命周期信息,因此也应负责决定局部结果何时失效、何时回接、何时报告路线层。

十六、从源码入口看:局部辅助、移动任务与外部服务如何分工

为了避免把这篇文章写成抽象的“自动避障介绍”,可以把源码阅读中的职责证据再展开一层。这里使用三个公开别名:LocalAvoidanceKernel 表示局部几何辅助,MoveToPointTask 表示构造参数并消费结果的移动任务,EntityScanner 表示提供附近候选的扫描服务。LocalAvoidanceKernel 是本文的职责别名,不对应源码中的唯一类名。

LocalAvoidanceKernel:参数少,结果也少

这个辅助入口的参数围绕当前局部求解组织,而非完整车辆实体。它需要知道当前点、目标方向、路线局部基准、扫描距离、距离路径的偏差、排除对象和避让设置;它无需持有整个路线对象,也无需知道任务何时完成。

其结果同样保持窄接口:一个新的二维方向,以及与当前候选相关的时间或速度反馈。结果不包含“下一步完整任务”,也不包含“新目的地”。窄接口使调用方可以继续保留自己的任务状态。

MoveToPointTask:拥有调用时机和消费路径

从调用职责看,可以把移动任务抽象为:组织目标调整、路径容差、分离计时和局部避让输入。局部计算完成后,移动任务可能替换当前分离向量、更新分离目标、请求导航 LOS 检查,并继续自己的速度混合、朝向处理、目标完成和停止逻辑。

这条链路表明,局部辅助属于移动任务内部的一段局部计算,并非“执行器前的总控制器”。任务仍然知道自己为何移动、当前目标是什么、什么时候可以退出以及局部状态何时失效。

EntityScanner 与路径服务:提供事实,不提供选择

实体扫描器提供附近的行人、车辆或对象列表,路径服务提供动态对象边界,导航跟踪器提供局部不可通行边缘。这些服务为局部避让提供事实,但不直接决定左转还是右转。

把事实提供者和选择者分开,有助于验证:扫描结果为空,可能是扫描器没有候选;候选被过滤,可能是局部资格条件;候选存在但没有安全方向,才是局部求解失败。若所有步骤都写在一个函数里,调试时只能看到“避让返回 false”,很难知道失败发生在哪一层。

调试绘制不等于运行时所有权

源码中的调试绘制可以显示障碍矩形、切线候选、导航阻挡边缘、碰撞圆和最终避让向量。这些输出对理解算法非常有价值,但它们只是观察路径。调试器画出了一个候选,不代表调试器拥有候选生成;调试器显示了碰撞时间,也不代表它负责决定任务是否等待。

这种区分同样适用于文章中的图。图可以把“扫描 → 预测 → 候选 → 评分 → 交付”画得很清楚,但图中的箭头表示职责关系,不要求所有模块合并成一个类。

十七、局部结果如何进入驾驶命令,而不越过 P3 与 P8

P3 已经定义,驾驶命令由多个来源在当前周期共同形成可消费契约。P7 产生的局部结果应当作为约束、局部目标或临时动作进入命令形成过程,不应直接覆盖整个命令结构。

三种常见交付形式

1. 方向偏移

局部层返回一个偏离原目标的方向,移动任务将其保存为当前局部分离目标。命令形成阶段可以继续结合路线方向、驾驶策略和车型能力。

2. 短时速度上限

当方向不适合立即改变,局部层可以提供等待或降低速度的约束。它表达“当前周期不要以原速度推进”,不直接生成最终刹车值。具体刹车如何解释,由车辆任务和执行器完成。

3. 临时等待状态

当左右候选都不具备安全条件时,任务可以进入等待或保持状态。等待既不代表路线完成,也不代表任务失败;它需要有效期、解除条件和升级条件。

局部结果与任务命令的合并

当前周期可能同时存在:

  • 路线层提供的局部目标;
  • P6 提供的等待成本和风险偏好;
  • P7 提供的即时冲突约束;
  • 玩家或 AI 提供的主要运动意图;
  • 车型执行器提供的可实现范围。

合并关系可以抽象为:

局部结果进入当前周期命令

局部避让不应该把自己写成命令的唯一来源。它只在当前空间冲突存在时提供短时约束;冲突结束后,命令链应当恢复对路线和主要控制源的正常消费。

为什么这对玩家车辆尤其重要

玩家保持油门或方向输入时,局部避让可以通过命令契约提供速度上限、等待状态或局部目标约束,但不应静默销毁玩家输入或改变驾驶权。若玩家车辆在近失事件后自动进入 AI 规避模式,玩家会感到控制权被抢走;若系统完全不提供任何安全约束,交通中的局部关系又无法保持。

合理边界既不是“玩家输入永远最高”,也不是“避让永远覆盖玩家”,而是由当前控制权规则明确规定哪些局部约束可以影响命令、影响的时间有多长,以及何时恢复原控制来源。

局部结果需要保留类型语义

“返回一个向量”对实现者很方便,对运行时诊断却不够。至少需要区分这个向量来自哪一种局部结果:避开动态实体、沿导航边缘修正、从等待状态恢复,还是任务本身改变了局部目标。不同来源可能拥有不同的有效期和清除条件。

例如,动态车辆暂时挡路时,结果可以随着对方速度变化而刷新;道路边界提供的限制可能在车辆离开该区域前持续存在;任务切换产生的临时目标则应在任务版本变化时立即失效。如果它们都被压成同一个二维方向,旧结果就可能在来源已经消失后继续影响当前命令。

目标运行时可以把局部结果抽象成窄契约:

结果类型 主要作用 失效条件
偏移方向 避开短时动态冲突 障碍消失、方向过期或任务变化
速度约束 降低推进风险 风险窗口结束或速度恢复条件满足
等待请求 暂停进入不可行空间 可行候选出现、等待超时或路线升级
受阻反馈 通知上层重新评估 路线层接收并生成新版本

这份契约不要求局部层知道完整路线,也不要求它理解所有车型动力学;它只让下游知道“本周期为什么不能照原方向推进,以及这个限制何时可以被清除”。


十八、P6 的策略如何影响 P7,但不能拥有 P7

P6 可以提供以下软输入:

  • 对等待的时间成本;
  • 对横向偏移的惩罚;
  • 对前方风险的评价权重;
  • 对保持路线或推进的偏好;
  • 车辆能力和驾驶者能力带来的调制范围。

P7 仍然拥有:

  • 障碍扫描;
  • 候选几何生成;
  • 碰撞时间计算;
  • 导航边缘检查;
  • 临时方向结果;
  • 避让成功、失败与恢复入口。

例如,积极策略可以降低等待成本,使一个几何上可行的侧向候选更容易被选中;但如果相邻车道的车辆边界已经与候选方向相交,积极策略不能跳过碰撞检查。保守策略可以提高风险惩罚,使系统更早选择等待;但等待动作仍然需要由下游任务执行。

因此 P6 到 P7 的接口应当是参数和偏好,不能是“策略直接指定左转十二度”。后者已经越过了局部几何和车型执行的所有权。


十九、源码阅读中的职责证据:怎样判断避让层在哪里

类名和文件名只能作为入口,不能直接证明所有权。判断局部避让职责时,可以沿四条证据链阅读。

谁收集障碍

如果附近行人来自角色智能扫描器,动态物体边界来自路径服务,导航阻挡来自导航跟踪器,那么局部避让只建立一次计算输入,不长期持有这些数据。

谁决定调用时机

如果移动任务根据目标状态、计时器、路径偏差和全局开关调用避让辅助,那么移动任务拥有运行节奏。避让模块本身不应被描述成每帧自动运行的常驻系统。

谁保存结果

如果返回向量被写入移动任务的分离目标,任务就是当前局部结果的持有者。若结果只作为调试绘制或一次性查询,它的生命周期更短。

谁决定完成与恢复

目标到达、停止精度、任务取消和路线回接如果都在移动任务中处理,就能确认局部避让只是执行中的一个中间阶段,并非高层任务。

公开文章可以把源码证据写成:

观察到的关系 可以抽象为 不应扩大为
辅助函数返回方向和时间 局部几何计算面 全局避让管理器
移动任务构造参数并消费结果 调用方拥有生命周期 辅助函数拥有路线
扫描器提供附近实体 外部服务提供候选 避让模块拥有世界实体
调试器绘制切线和障碍 可观测性输出 调试器决定避让策略

二十、玩家体验中的“顺滑”来自局部状态连续

玩家不会看到切线公式,也不会看到候选评分。但玩家会感受到:

  • 车辆是否在障碍出现后及时反应;
  • 反应是否过度,是否突然左右摆动;
  • 车辆是否会因为一个短时对象重建整条路线;
  • 障碍消失后是否自然回到目标方向;
  • 玩家保持油门时,系统是否在必要时提供合理的安全约束;
  • AI 车辆是否在相似场景下表现出可解释的差异。

这些体验并非由单个转向函数决定,而是由多个状态连续性共同产生:路线连续、局部目标连续、风险窗口连续、执行器反馈连续。局部避让如果每次更新都重新选择完全不同的一侧,即使几何上没有碰撞,玩家也会感到车辆犹豫。

因此,局部候选评分不仅要考虑当前最优方向,还要考虑与上一周期方向的连续性。这个约束不一定直接写在避让辅助中,也可能由调用任务保存上一结果并限制候选变化。


二十一、三个运行时案例:同一个局部算法如何面对不同冲突

前面的模型如果只停留在“障碍进入、候选生成、结果评分”,仍然容易被理解成一段静态几何算法。实际运行时更重要的是:同样的局部辅助,会被不同任务以不同上下文调用。下面用三个案例把路线、策略、扫描、局部结果和恢复关系串起来。

案例一:行人横穿当前路线

车辆沿主干道接近路口,路线和目标均未变化。一名行人从车辆右前方横向进入道路。实体扫描器先返回行人候选;过滤阶段确认行人处于同一高度层、未被排除、速度和位置满足当前扫描范围,因此候选进入圆形预测。

如果行人的相对速度使预计碰撞时间较短,局部层会根据行人未来位置生成左、右切线。右侧可能被路缘或另一辆车的动态边界限制,左侧则保留一个偏离目标方向较小的候选。策略层的等待成本可以影响“等待还是绕行”的排序,但不能取消行人边界的硬检查。

移动任务消费结果后,可以采取三种不同方式:降低当前局部目标速度、生成短时侧向分离目标,或在候选不足时保持等待。行人离开车辆走廊后,行人引用和临时分离结果都需要清除,路线目标重新成为局部方向的主要来源。

这个案例证明:局部避让并没有改变车辆要去的地方。它只处理一段时间窗口内的空间冲突。

案例二:前车停止,旁边车道也不确定

车辆沿路线驶入拥堵路段,前车速度快速下降。扫描器得到前车的动态边界和速度,局部预测确认继续保持原方向会使碰撞时间不断缩短。此时策略层可能偏好保持路线、减少横向动作,也可能因为当前驾驶者更积极而降低等待成本。

局部层需要检查相邻车道的车辆边界、路径走廊和道路边缘。如果两侧候选都存在几何风险,积极策略也只能选择减速或等待。如果左侧可行但偏离路线较大,评分函数会把方向偏差作为软代价;如果右侧完全被硬边界排除,右侧不应进入最终排序。

前车重新开始移动后,局部结果不应继续保持。移动任务需要判断障碍解除的持续时间,逐步清除分离目标,并把跟车或路线目标重新接入。若前车始终停止且队列持续增长,路线层才可能收到受阻报告,决定是否重新评估路线。

案例三:玩家车辆发生近失,但仍由玩家控制

玩家驾驶车辆高速通过路口,另一辆 AI 车辆与玩家车辆的扩展边界短时接近,但没有实际碰撞。玩家信息路径可以记录近失时间、对象和相关统计,也可以触发特殊能力、语音或警示。AI 车辆的局部避让任务则可能消费玩家车辆作为扫描候选,并决定自己的减速或鸣笛行为。

这两个方向不能混为一谈:AI 车辆避让属于自动驾驶命令链;玩家车辆近失属于玩家信息观察链。玩家仍然拥有当前主要命令提交权,系统不能因为记录了近失,就让玩家车辆的控制源自动切换成 AI。

这个案例也说明“风险状态”的所有权必须单独追踪。一个近失记录可以由统计系统消费,但不一定拥有车辆任务;一个鸣笛标志可以由 AI 车辆读取,但不一定产生新的路线;一个高速路标志可以影响音频或交通响应,但不必进入玩家输入解释。

三个案例的共同结构

三个场景的障碍类型和消费者不同,但都遵循同一条关系:

路线有效时的局部风险处理链

区别发生在候选来源、策略输入、控制源和下游消费者;局部避让仍然承担短时空间处理职责。

迟到结果的版本校验

二十二、时间窗口、去重与迟到结果

局部避让并非一次函数调用即可结束的同步过程。对象扫描、碰撞预测、任务更新和物理反馈可能处于不同时间点。要维持连续行为,运行时需要明确哪些结果还有效。

扫描结果的有效期

一个对象在上一周期进入候选,不代表它在当前周期仍然占据同一位置。对高速对象,旧扫描结果可能已经足够过期;对低速或静止物体,结果可以在短时间内复用。有效期需要与相对速度、扫描距离和任务阶段共同决定。

同一个冲突的去重

一个对象可能连续多个周期触发预测。如果每次都把它当成新的事件,调试日志会快速膨胀,任务也可能重复重置分离状态。运行时可以通过实体标识、时间窗口、冲突阶段和上一次结果进行去重,但去重不应阻止几何结果随位置变化而更新。

迟到的局部结果

如果局部计算在一个周期开始时读取了障碍,返回时车辆已经换道、任务已经取消或对象已经消失,旧结果就不能直接覆盖当前任务状态。在目标运行时中,建议为结果附带计算时的目标方向、任务阶段或有效版本。

这和 P5 的异步路线请求是同一种系统问题,只是时间尺度更短:路线请求防止旧搜索结果覆盖新路线;局部避让防止旧几何结果覆盖新目标。两者都需要把“结果是什么”与“结果属于哪个上下文”分开保存。

为什么不能把所有临时状态塞进一个缓存

扫描缓存、碰撞预测结果、分离向量和路线目标的有效期不同。把它们放在一个“当前避让状态”对象里,清理时容易出现两种错误:清理太早导致车辆突然失去目标,清理太晚导致旧障碍继续影响车辆。更稳妥的方式是分别记录来源、版本、有效期和清除条件。

二十三、失败设计:让局部避让承担整个驾驶系统

局部避让容易成为“哪里无法通过就在哪里追加逻辑”的集中点。下面几种方案虽然短期能让车辆避开一个障碍,却会破坏运行时边界。

失败一:每个障碍都触发完整路线搜索

这会把短时动态对象升级为全局导航事件,造成异步请求爆发和路线抖动。正确做法是先在局部走廊内尝试等待、制动或偏移,只有持续受阻或道路结构失效时才通知路线层。

失败二:局部层直接写入转向和踏板控制

这样可以快速观察到车辆的规避动作,但会绕过 P3 的命令契约、P6 的软偏好和 P8 的车型执行器。车辆换成船、摩托或飞机后,局部层会被迫理解每一种控制律,最终变成不可维护的总控制器。

失败三:把所有附近实体都视为障碍

这会导致车内角色、不同高度对象、挂接对象和无关装饰持续触发避让。障碍资格必须由实体关系、路径服务、任务状态和导航能力共同确定,不能只按距离截取一张列表。

失败四:用一个“正在避让”字段覆盖所有阶段

等待、侧向绕行、候选失败、路线受阻和恢复的清理条件不同。一个布尔值无法表达临时方向是否仍有效,也无法判断失败后应该重试、回接还是升级到重规划。

失败五:把玩家风险观察接入 AI 控制源

玩家闯红灯、近失或逆行可以成为统计、警示和交通响应的输入,但不应自动替换玩家的命令来源。观察者记录和控制者仲裁必须保持分离。

这些失败设计的共同问题,是把不同时间尺度和不同所有权的状态压进同一个局部模块。局部避让越接近“万能驾驶器”,越难解释它为什么在某个阶段改变了车辆行为。

二十四、验证局部避让不能只看“是否撞上”

一个合格的 P7 验证矩阵至少应覆盖以下维度:

障碍类型

分别测试行人、车辆、动态物体、导航边缘和火焰等能力标记控制的特殊风险。确认过滤条件不会把不同类型都压成同一个圆形障碍。

相对运动

固定车辆路线,改变障碍的横向速度、同向速度和静止状态。检查碰撞时间、候选生成和等待行为是否具有合理差异。

路线边界

在左右两侧分别设置可行空间、路缘和不可通行区域,确认候选评分不会把被硬边界排除的方向重新选回来。

策略偏好

固定几何条件,只改变 P6 的等待成本和横向偏好。确认偏好只改变可行候选之间的排序,不会允许几何冲突候选通过。

速度与刷新周期

比较低速、高速和接近停止状态。确认避让前视窗口、扫描频率和紧急阈值不会在速度变化后失去意义。

结果恢复

障碍出现、持续、消失,再观察车辆是否回接原路线;中途取消任务或目标变化时,临时避让状态是否清除。

玩家路径隔离

在玩家保持输入时制造近失和碰撞上下文,确认风险记录、警示和统计能够更新,同时确认玩家控制源未被替换为 AI 避让命令。

验证日志至少应记录:

  • 当前路线版本;
  • 当前局部目标;
  • 候选障碍类型和过滤原因;
  • 预计碰撞时间与接近速度;
  • 左右候选及排除原因;
  • P6 提供的软偏好;
  • 最终交付给任务的向量或等待状态;
  • P8 执行器是否接受;
  • 临时状态的建立和清除时间。

这样才能把“车辆撞了”拆成可定位的链路:没扫描到、被错误过滤、预测时间错误、候选被误选、任务没有消费、执行器拒绝,还是物理反馈导致失效。

验证还应包含反例,而非只验证成功绕行:故意让左右两侧都不可行,检查系统是否进入等待或上报受阻;让障碍在求解中途消失,检查迟到结果是否被丢弃;让任务目标在局部偏移期间改变,检查旧路线方向是否被清除;让车辆切换类型或控制源,检查局部结果是否仍然通过正确的命令契约。只有把这些中断、取消和恢复路径纳入测试,才能证明局部避让是一个有生命周期的运行时,而非一段只在演示场景里有效的转向公式。


二十五、P7 与 P5、P6、P8 的最终边界

四篇的关系可以收束为:

P5、P6、P7 与 P8 的职责边界

P7 不负责:

  • 创建目的地和全局路线;
  • 维护驾驶个性和长期风险档案;
  • 直接生成油门、制动和转向最终值;
  • 解释轮胎、浮力、旋翼或固定翼控制;
  • 处理网络权威、回放和远景实体生命周期。

P7 负责的是一段短时、可恢复、可观测的空间关系:当前障碍是什么,冲突何时可能发生,哪些方向仍可行,当前应当等待还是偏移,以及如何把局部结果交回原有任务。


二十六、迁移到目标运行时:先保留接缝,再决定算法

在目标引擎中重建局部避让,不应从“写一个避障函数”开始,而应先固定几条边界:

  1. 由移动任务决定避让的调用时机和有效期;
  2. 由扫描服务提供候选实体,避免避让模块遍历世界;
  3. 由几何查询层提供圆形、盒状和导航边缘测试;
  4. 由评分层返回局部方向、风险反馈和状态结果;
  5. 由任务负责把结果转换成局部目标并在完成后清除;
  6. 由车型执行器决定这个局部意图能否被当前载具实现;
  7. 由路线层接收持续受阻反馈并决定是否重规划。

这种迁移顺序可以先建立可观测的纯计算模块,再接入真实扫描和执行器。局部避让原型未必一开始就拥有全部车辆物理,但必须能回答:输入了哪些障碍,为什么排除某个候选,为什么选择左侧,何时释放临时方向。

如果一开始就把避让写进车辆控制器,后续会很难区分几何失败、任务消费失败和物理执行失败。接缝先固定,算法才有可替换空间。


二十七、AI 协作复盘:把“局部规避”拆成可验证关系

局部避让材料很容易被压缩成“自动避障系统”这一概念,但这种概括既不能解释源码,也不能指导迁移。AI 在本篇中的作用,是把不同来源的几何、任务和玩家风险材料对齐成一条可复核链:

  • 谁拥有附近实体列表;
  • 哪些对象有资格成为当前障碍;
  • 圆形、盒状和导航边缘分别使用什么近似;
  • 碰撞时间和接近速度如何进入评分;
  • 左右候选由谁生成、由谁限制;
  • 局部结果由哪个任务保存和消费;
  • 避让失败何时只是等待,何时升级为路线重规划;
  • 玩家近失记录为什么不等于 AI 控制权。

人仍然需要决定哪些是代码直接证明,哪些只是调用关系抽象,哪些必须等待目标原型验证。AI 的价值不是把局部避让包装成一个万能模块,而是帮助保留每个短时结果的输入、消费者和失效条件。

局部避让不负责重新选择车辆目的地;它在目标仍然有效时,为当前空间冲突提供可恢复的下一步。


二十八、结语:一辆车如何在保持目的地的同时处理眼前世界

开放世界中的障碍不会按照路线请求的时间表出现。行人突然横穿,前车临时停止,动态物体进入道路,导航边缘阻挡了原本可以通过的偏移方向。车辆如果只有全局路线,就会在局部冲突前停住;如果只有局部避让,又会失去目的地和任务关系。

稳定的车辆运行时需要把两者接起来:路线保留较长时间的方向,策略描述不同驾驶者的取舍,局部避让在一个较短时间窗口内收集候选、预测冲突、生成方向并交付给当前任务。冲突结束后,临时状态释放,原目标继续生效;冲突持续到超出局部能力时,受阻信息再返回路线层。

P5 解决“车辆如何持续知道该去哪里”,P6 解决“同一条路线为什么产生不同驾驶选择”,P7 解决“当前空间发生变化时还能怎么走”。下一篇 P8 将继续追问:当局部任务已经给出方向、速度或等待意图后,车型执行器如何把它们转换为真实的控制量,并跨过物理系统的接缝。

发表评论

了解 AI Native Game Development 的更多信息

立即订阅以继续阅读并访问完整档案。

继续阅读