CD Code Digest Hub /GTA V · v2

车辆 AI、路网、交通灯、录像与 GPS

75 分钟阅读 16 个章节 1 张图

本页解释车辆如何“认路和开车”:框架层 fwvehicleai 定义的路网节点/链接/区域二进制格式;游戏层 CPathFind(全局单例 ThePaths)如何作为流式模块按区域装载路网、如何用 A* 做路线搜索;CVehicleIntelligence 与车辆任务树(vehicleAi/task)如何把“目标”变成节点列表、follow route 与每帧的转向/油门/刹车;避障与延迟(多线程)任务;路口 CJunctions 与交通灯 CTrafficLights 的相位逻辑;以及车辆录像(CVehicleRecordingMgr)、航点录像(CWaypointRecording)、路线池(Route.h)与玩家 GPS(CGps)。

父页面见 vehicle-architecture.md;dummy/superdummy 如何依赖本页的 follow route 见 vehicle-physics-handling-damage.md 第 4.2、8 节。

背景与相关页面#

相关源码文件#

文件作用
rage/framework/src/fwvehicleai/pathfindtypes.h/.cpp、pathregion.pscCNodeAddress、CPathNode、CPathNodeLink、CPathVirtualJunction、CPathRegion(资源格式)
game/vehicleAi/pathfind.h/.cpp、pathfind_shared.cpp、Pathfind_Build.*、PathfindNodeSearchJob.cpp、PathfindNodeSearchSPU*.{job,cpp}CPathFind/ThePaths:流式、查询、A* 搜索、GPS 路线、离线构建、异步最近节点搜索
game/vehicleAi/VehicleIntelligence*.*、VehMission.h、VehicleNodeList.*车辆 AI 本体、任务/驾驶标志枚举、节点列表
game/vehicleAi/task/*车辆任务(巡航、前往、避障、停车、追逐、飞行、玩家驾驶、录像跟随…)与延迟任务
game/task/System/TaskHelpers.h/.cppCPathNodeRouteSearchHelper、CRoutePoint、CVehicleFollowRouteHelper
game/vehicleAi/junctions.*、junctions.psc、JunctionEditor.*路口实例、模板、相位、铁路道口
game/control/trafficlights.*交通灯周期、渲染、TrafficLightInfos 扩展
game/control/record.*、rage/framework/src/fwcontrol/record.h车辆录像录制与回放
game/control/WaypointRecording*.*、rage/framework/src/fwcontrol/WaypointRecordingRoute.h航点录像(ped/车辆)
game/control/Route.*CPointRoute/CPatrolRoute 池
game/control/gps.*玩家 GPS 槽位
game/vehicleAi/driverpersonality.*、FlyingVehicleAvoidance.*、roadspeedzone.*、pathzones.*、racingline.*、VehicleNavigationHelper.*驾驶员个性、飞行器互相避让、道路限速区、路径区域、赛车线、无路网导航辅助

1. 分层视图#

证据:车辆任务管理器 src/dev_ng/game/task/System/TaskManager.h:76-92;CVehicleIntelligence::Process 调用 m_TaskManager.Process src/dev_ng/game/vehicleAi/VehicleIntelligence.cpp:1104-1106;巡航任务持有路线搜索助手与 follow route src/dev_ng/game/vehicleAi/task/TaskVehicleCruise.h:239-247;路线搜索调用 ThePaths.DoPathSearch src/dev_ng/game/task/System/TaskHelpers.cpp:2974-2990;区域数组 src/dev_ng/game/vehicleAi/pathfind.h:1175;节点列表容量 src/dev_ng/game/vehicleAi/VehicleNodeList.h:55-56;follow route 容量 src/dev_ng/game/task/System/TaskHelpers.h:1200;避障任务的延迟回调 src/dev_ng/game/vehicleAi/task/TaskVehicleGoToAutomobile.h:286-288;dummy 用 follow route 采样虚拟路面 src/dev_ng/game/Vehicles/Automobile.cpp:8364-8436。ped→车辆任务的下发细节归 07 章,图中该边仅示意。

2. 路网数据格式(fwvehicleai)#

2.1 区域与节点地址#

地图被切成 PATHFINDMAPSPLIT × PATHFINDMAPSPLIT = 32 × 32 = 1024 个区域,每区最多 MAXNODESPERREGION = 10240 个节点、MAXLINKSPERREGION = 32768 条链接、256 个路口、65536 个高度样本 src/dev_ng/rage/framework/src/fwvehicleai/pathfindtypes.h:30-41。坐标压缩:XY 以 s16 存储、×4(0.25m 精度),Z 以 u16 存储、×32(注释:从 64 降到 32 以支持 ±1024m 高度)src/dev_ng/rage/framework/src/fwvehicleai/pathfindtypes.h:43-56。

CNodeAddress 是 32 位的 {region:16, index:16},全 1 表示空 src/dev_ng/rage/framework/src/fwvehicleai/pathfindtypes.h:62-123。注意:头部注释说“高 6 位为区域、低 10 位为索引,每区只能 1000 个节点”,与实际 16/16 位域及 10240 上限不符——注释是旧版设计遗留 src/dev_ng/rage/framework/src/fwvehicleai/pathfindtypes.h:25-29。

2.2 CPathNode(32 字节)#

在 360/PS3 向量化路径下编译期断言 sizeof(CPathNode) == 32 且 16 字节对齐,以便单条 lvlx 指令解包坐标 src/dev_ng/rage/framework/src/fwvehicleai/pathfindtypes.h:374-397。字段:搜索用的 m_pNext/m_pPrevious 与 m_distanceToTarget(运行时,不序列化)、地址、街道名哈希、链接起始索引、XY 坐标,以及两个打包 u32 src/dev_ng/rage/framework/src/fwvehicleai/pathfindtypes.h:226-288、src/dev_ng/rage/framework/src/fwvehicleai/pathfindtypes.h:354-370:

位域含义
m_1: m_group(3) m_Offroad m_onPlayersRoad m_noBigVehicles m_cannotGoRight/Left m_slipLane m_indicateKeepLeft/Right m_specialFunction(5) m_coorsZ(16)洪水填充组、越野、玩家道路标记(人口用)、禁大车、转向限制、匝道、GPS 提示、特殊功能、Z
m_2: m_noGps m_closeToCamera m_slipJunction m_alreadyFound m_switchedOffOriginal m_waterNode m_highwayOrLowBridge m_switchedOff m_qualifiesAsJunction m_speed(2) m_numLinks(5) m_inTunnel m_distanceHash(7) m_density(4) m_deadEndness(3) m_leftOnlyGPS 屏蔽、开关状态、水面、高速、路口、速度档(慢/正常/快/双倍)、链接数、隧道、7m 间距哈希、密度 0–15、死路程度

特殊功能枚举(停车位、加油站、行人过街、交通灯、让行、强制/伪路口、禁区、禁止生成车辆…)上限 31(5 位)src/dev_ng/rage/framework/src/fwvehicleai/pathfindtypes.h:126-153。HasSpecialFunction_Driving() 把交通灯/让行等“普通交通用途”排除在外 src/dev_ng/rage/framework/src/fwvehicleai/pathfindtypes.h:335-344。

2.3 CPathNodeLink(8 字节)#

m_OtherNode + 一个打包 u32:GPS 双向、无车道时阻断、侧倾 m_Tilt(5) 与衰减、窄路、通向/来自死路(为 SPU 预计算)、中央宽度 m_Width(4,值 15 表示所有车道走中线的小巷)、不用于导航(并道/匝道连接段)、捷径、双向车道数(各 3 位)、距离(8) src/dev_ng/rage/framework/src/fwvehicleai/pathfindtypes.h:407-501。车道宽 5.4m(窄路 4.0m),车道中心偏移由车道数与中央宽度推导 src/dev_ng/rage/framework/src/fwvehicleai/pathfindtypes.h:407-409、src/dev_ng/rage/framework/src/fwvehicleai/pathfindtypes.h:444-486。

2.4 CPathRegion 与虚拟路口#

CPathRegion : pgBase 是一个可重定位资源:节点数组(车辆节点在前、行人节点在后)、链接数组、虚拟路口 CPathVirtualJunction(路口区域的高度栅格,用于 dummy 车在路口内的路面高度)、高度样本、atBinaryMap 路口映射 src/dev_ng/rage/framework/src/fwvehicleai/pathfindtypes.h:504-591。__DEV/RAGEBUILDER/资源编译器构建可从 XML 读写区域 src/dev_ng/rage/framework/src/fwvehicleai/pathfindtypes.h:554-562;离线构建器 CPathFindBuild : CPathFind 负责节点排序、合并、开放空间节点、距离哈希洪水填充与保存 src/dev_ng/game/vehicleAi/Pathfind_Build.h:22-49。

3. CPathFind:流式模块与查询#

3.1 作为流式模块#

CPathFind : strStreamingModule,全局实例 ThePaths src/dev_ng/game/vehicleAi/pathfind.h:215、src/dev_ng/game/vehicleAi/pathfind.h:1329。注册与生命周期:

时机调用证据
启动注册流式模块CPathFind::RegisterStreamingModule → AddModule(&ThePaths)src/dev_ng/game/core/game.cpp:581、src/dev_ng/game/vehicleAi/pathfind.cpp:13873-13876
核心初始化CScene 中 ThePaths.Init(INIT_CORE);会话初始化经 CPathFindWrapper::Initsrc/dev_ng/game/scene/scene.cpp:629、src/dev_ng/game/core/game.cpp:2325
不存在的区域注册为 DEGENERATEPATHREGION 哑对象(同样处理“传家宝岛”区域,偏移 sm_iHeistsOffset = PATHFINDREGIONS)src/dev_ng/game/vehicleAi/pathfind.cpp:13878-13900、src/dev_ng/game/vehicleAi/pathfind.cpp:126
放置PlaceResource → pgRscBuilder::PlaceStream → Loadsrc/dev_ng/game/vehicleAi/pathfind.cpp:337-353
装载设置 apRegions[i],把每个节点的 m_distanceToTarget 置为 PF_VERYLARGENUMBER,并重放所有尚未撤销的脚本节点开关src/dev_ng/game/vehicleAi/pathfind.cpp:360-404
卸载Unload 并删除区域对象src/dev_ng/game/vehicleAi/pathfind.cpp:306-330

3.2 UpdateStreaming#

由 CStreaming 更新循环调用 src/dev_ng/game/streaming/streaming.cpp:783-784,每 512ms 才真正执行一次((time & ~511) != (prevTime & ~511)),或在强制时立即执行 src/dev_ng/game/vehicleAi/pathfind.cpp:12380-12384。步骤:清空待流送标记;bLoadAllRegions 时标记全部;否则以焦点实体(或玩家切换目标)为中心标记 STREAMING_PATH_NODES_DIST_PLAYER = 1765m 内的区域,保留 GPS 周期/起止异步搜索周围的区域(1765/150m),再遍历车辆池为 AI 车辆标记周围区域 src/dev_ng/game/vehicleAi/pathfind.cpp:12386-12470、src/dev_ng/game/vehicleAi/pathfind.h:50-52。另外脚本、游戏与地图可通过 AddNodesRequiredRegionThisFrame 声明每帧必需区域(地图 4、脚本 12、游戏 20 个槽)src/dev_ng/game/vehicleAi/pathfind.h:295-324、src/dev_ng/game/vehicleAi/pathfind.cpp:12218。切换到/离开传家宝岛地图时,会清除所有区域的必需标志并 StreamingRemove 主图与岛图的全部区域,再强制重载 src/dev_ng/game/vehicleAi/pathfind.cpp:12344-12378。

每帧 CScene::Update 中 ThePaths.Update() 仅调用 UpdateUsedNodes(加调试工具)src/dev_ng/game/scene/scene.cpp:825-826、src/dev_ng/game/vehicleAi/pathfind.cpp:613-635。

3.3 DoPathSearch:A*(从目标反向搜索)#

DoPathSearch 的参数包括起点坐标/节点、目标坐标、输出节点数组与请求数、截止距离、最大搜索距离、不逆行、避开节点、两栖/船、GPS 模式、捷径、忽略关闭节点、遵守交规、偏好目标节点列表、避高速/禁区/越野,以及输出每节点车道偏移与宽度 src/dev_ng/game/vehicleAi/pathfind.cpp:1023-1030。实现要点:

  • 反向:先把目标节点放入 OPEN 集,直到弹出起点节点为止;每个节点的累计代价存在节点自身的 m_distanceToTarget 中,结束后用 aNodesToBeCleared(最多 PF_MAXNUMNODES_INSEARCH = 5000)把访问过的节点复位 src/dev_ng/game/vehicleAi/pathfind.cpp:1206-1228、src/dev_ng/game/vehicleAi/pathfind.cpp:985、src/dev_ng/game/vehicleAi/pathfind.h:1161。回溯时从起点沿“邻居距离 = 本节点距离 − 链接长度”的边走向目标,因此输出天然是从起点到目标的顺序 src/dev_ng/game/vehicleAi/pathfind.cpp:1896。
  • 桶式优先队列:OPEN 集是按“累计代价 + 启发值”取模 PF_HASHLISTENTRIES = 512 的哈希桶链表;维护当前最小/最大估价,最小值所在桶即下一个扩展对象;当估价范围超过 512 时才需要逐个校验节点估价 src/dev_ng/game/vehicleAi/pathfind.cpp:1247-1292、src/dev_ng/game/vehicleAi/pathfind.h:48。
  • 启发函数:0.9 × 欧氏距离(0.9 来自构建器中快速道路的距离系数,保证低估),注释比较了 Chebyshev 与对角近似并说明取舍 src/dev_ng/game/vehicleAi/pathfind.cpp:987-1021。
  • 保护:迭代超过 50000 次断言并跳出 src/dev_ng/game/vehicleAi/pathfind.cpp:1241-1245;__BANK 记录最近 16 次搜索历史与耗时 src/dev_ng/game/vehicleAi/pathfind.cpp:1034-1060、src/dev_ng/game/vehicleAi/pathfind.h:326-330。

AI 车辆不会一次性搜索全程:CPathNodeRouteSearchHelper 只请求 CAR_MAX_NUM_PATHNODES_STORED − 已保留节点数 个节点(最多 14),因此车辆是以“滚动窗口”方式持续重搜(推断,依据请求数与节点列表容量)src/dev_ng/game/task/System/TaskHelpers.cpp:2974-2984。区域未加载且允许等待时,搜索助手停留在 State_Searching src/dev_ng/game/task/System/TaskHelpers.cpp:2964-2970。

3.4 其他查询#

  • FindNodeClosestToCoors(带回调过滤版本)与按方向/车道等多种节点查询 src/dev_ng/game/vehicleAi/pathfind.cpp:7434、src/dev_ng/game/vehicleAi/pathfind.cpp:7558。
  • 异步最近节点搜索:StartAsyncGPSSearch 把参数(含 GPS 禁用区)打包成 sysTaskParameters,以 sysTaskManager::Create(TASK_INTERFACE(PathfindNodeSearchSPU), ...) 启动;PS3 额外把区域指针表作为只读 DMA 输入并给 180KB scratch src/dev_ng/game/vehicleAi/pathfind.cpp:7671-7707。注意 PathfindNodeSearchJob.cpp 的头注释写的是“Vehicle population SPU update”,与实际内容不符(复制遗留)src/dev_ng/game/vehicleAi/PathfindNodeSearchJob.cpp:1-2。
  • 节点开关:脚本可在区域内关闭/恢复道路(SwitchRoadsOffInArea),最多 MAX_NUM_NODE_SWITCHES = 100 条记录,任务结束时按脚本线程撤销 src/dev_ng/game/vehicleAi/pathfind.cpp:10883、src/dev_ng/game/vehicleAi/pathfind.h:54-56、src/dev_ng/game/vehicleAi/pathfind.h:140-143。
  • FindStreetNameAtPosition 仅在 PS4/PC/XB1 编译 src/dev_ng/game/vehicleAi/pathfind.cpp:10581-10587。

4. CVehicleIntelligence#

4.1 组成#

CVehicleIntelligence 使用池(与车辆池同大小、按最大子类分配)src/dev_ng/game/vehicleAi/VehicleIntelligence.cpp:81,工厂按车型创建直升机/飞机子类 src/dev_ng/game/vehicleAi/VehicleIntelligenceFactory.cpp:20-32。主要成员:任务管理器 CVehicleTaskManager m_TaskManager src/dev_ng/game/vehicleAi/VehicleIntelligence.h:799;车辆/行人/物体扫描器;一组 CExpensiveProcess 分摊器(转向、刹车、变道、dummy 避让、跟车、导航网格视线、路口更新、警笛反应),把昂贵计算分散到不同帧 src/dev_ng/game/vehicleAi/VehicleIntelligence.h:373-384、src/dev_ng/game/vehicleAi/VehicleIntelligence.cpp:259-280;车辆事件组;“前方挡路车”;备用 follow route m_BackupFollowRoute(任务丢失时给 superdummy 用)src/dev_ng/game/vehicleAi/VehicleIntelligence.h:386-392。

4.2 Process 与收尾#

CVehicleIntelligence::Process src/dev_ng/game/vehicleAi/VehicleIntelligence.cpp:985-1126:

  1. 每帧都立即传播“身后车辆数”;非全量帧到此为止 src/dev_ng/game/vehicleAi/VehicleIntelligence.cpp:987-993。
  2. 重置每帧标志(警告行人、允许 dummy、时间片许可等——任务需在本次更新中重新声明是否允许时间片)src/dev_ng/game/vehicleAi/VehicleIntelligence.cpp:995-1008。
  3. 坦克/曾被玩家拥有的飞行器在无人驾驶时、或需要为警笛让路时,强制其他车辆为其停车 src/dev_ng/game/vehicleAi/VehicleIntelligence.cpp:1010-1015。
  4. 船只避让助手;路口更新由分摊器决定是否本帧执行 src/dev_ng/game/vehicleAi/VehicleIntelligence.cpp:1022-1029。
  5. 网络克隆只更新附近实体列表与路口后返回(AI 在拥有者端运行)src/dev_ng/game/vehicleAi/VehicleIntelligence.cpp:1031-1042。
  6. 爆炸击飞的车在物理停止前禁止转 dummy;假乘员车任务丢失时重建默认任务;处理 dummy 标志 src/dev_ng/game/vehicleAi/VehicleIntelligence.cpp:1044-1063。
  7. 若在播放“不使用 AI”的录像:失效缓存的节点列表/路线、标记避让脏、只处理事件与任务(让敞篷顶等仍工作);否则正常流程:预更新、路口、身后车、重置变量、附近实体、失效缓存、停滞计时、事件、m_TaskManager.Process src/dev_ng/game/vehicleAi/VehicleIntelligence.cpp:1065-1107。
  8. 非 PS3 上把收尾排入 g_VehicleIntelligenceProcess 延迟任务 src/dev_ng/game/vehicleAi/VehicleIntelligence.cpp:1109-1125。

收尾 Process_OnDeferredTaskCompletion 缓存当前任务的节点列表与 follow route(避免后续反复查询任务树),停放车请求时间片,并对 dummy 车做安全检查:若任务禁止 dummy、follow route 少于两个点(且物理激活)或约束剧变,则尝试转回 real;转不回且没有路线时停用物理 src/dev_ng/game/vehicleAi/VehicleIntelligence.cpp:1128-1199。

5. 车辆任务#

5.1 任务参数与驾驶标志#

所有车辆任务派生自 CTaskVehicleMissionBase : CTask,持有 sVehicleMissionParams:目标实体或位置、到达距离、驾驶标志、巡航速度、最大巡航速度、目标障碍尺寸系数;默认驾驶模式 DMode_StopForCars src/dev_ng/game/vehicleAi/task/TaskVehicleMissionBase.h:28-70、src/dev_ng/game/vehicleAi/task/TaskVehicleMissionBase.h:238-296。任务可声明网络同步/可迁移并提供序列化器 src/dev_ng/game/vehicleAi/task/TaskVehicleMissionBase.h:320-330。

DrivingFlags 是一个 32 位位集(停车让车/让人、绕行、走对向车道、倒车、禁区回避、调整路速、捷径、变道、使用关闭节点、偏好导航网格、飞机滑行、强制直线、路口拉线、避高速、完成后不终止等),并组合出脚本可用的驾驶模式;注释要求同步修改脚本头 commands_vehicle.sch src/dev_ng/game/vehicleAi/VehMission.h:93-151。旧式任务类型 VehMissionType 与临时动作 VehTempActType 仍作为脚本/网络使用的枚举存在 src/dev_ng/game/vehicleAi/VehMission.h:5-91。

5.2 任务族#

类别代表类证据
巡航/前往(核心)CTaskVehicleCruiseNew、CTaskVehicleGoToAutomobileNew、CTaskVehicleFleesrc/dev_ng/game/vehicleAi/task/TaskVehicleCruise.h:26、src/dev_ng/game/vehicleAi/task/TaskVehicleCruise.h:178、src/dev_ng/game/vehicleAi/task/TaskVehicleCruise.h:452
底层驾驶CTaskVehicleGoToPointWithAvoidanceAutomobile、CTaskVehicleGoToPointAutomobile、CTaskVehicleGoToNavmeshsrc/dev_ng/game/vehicleAi/task/TaskVehicleGoToAutomobile.h:80、src/dev_ng/game/vehicleAi/task/TaskVehicleGoToAutomobile.h:552、src/dev_ng/game/vehicleAi/task/TaskVehicleGoToAutomobile.h:603
长距离CTaskVehicleGotoLongRange(分段请求节点区域后再前往中间目标,时间片帧也持续请求)src/dev_ng/game/vehicleAi/task/TaskVehicleGoToLongRange.h:6-67
飞行/水上/潜艇直升机/飞机/船/潜艇前往、降落、悬停、坠毁、空中逃离、追机src/dev_ng/game/vehicleAi/task/TaskVehicleGoToHelicopter.h:20、src/dev_ng/game/vehicleAi/task/TaskVehicleGoToPlane.h:20、src/dev_ng/game/vehicleAi/task/TaskVehicleGotoBoat.h:14、src/dev_ng/game/vehicleAi/task/TaskVehicleGoToSubmarine.h:17、src/dev_ng/game/vehicleAi/task/TaskVehicleFlying.h:25-234
战斗/追逐/执法攻击、坦克攻击、追击、冲撞、阻挡、包围、护航、并行、警察行为(车/直升机/船)、直升机护卫src/dev_ng/game/vehicleAi/task/TaskVehicleAttack.h:23、src/dev_ng/game/vehicleAi/task/TaskVehiclePursue.h:23、src/dev_ng/game/vehicleAi/task/TaskVehicleRam.h:17、src/dev_ng/game/vehicleAi/task/TaskVehicleBlock.h:15、src/dev_ng/game/vehicleAi/task/TaskVehicleEscort.h:24、src/dev_ng/game/vehicleAi/task/TaskVehiclePoliceBehaviour.h:21-145
停车/停止停车、靠边、乘客下车、新停车逻辑、对警笛反应、三点掉头src/dev_ng/game/vehicleAi/task/TaskVehiclePark.h:24-428、src/dev_ng/game/vehicleAi/task/TaskVehicleThreePointTurn.h:24
临时动作等待/倒车/刹车/手刹/转向/前进/急转/飞向/迎头碰撞/助推/沿点路径/烧胎/轰油门/上浮src/dev_ng/game/vehicleAi/task/TaskVehicleTempAction.h:25-817
录像CTaskVehicleFollowRecording、CTaskVehicleFollowWaypointRecordingsrc/dev_ng/game/vehicleAi/task/TaskVehicleFollowRecording.h:21、src/dev_ng/game/vehicleAi/task/TaskVehicleFollowRecording.h:65
无人/死亡司机/爆胎/打滑CTaskVehicleNoDriver、CTaskVehicleDeadDriver、CTaskVehicleShotTire、CTaskVehicleSpinOutsrc/dev_ng/game/vehicleAi/task/TaskVehiclePlayer.h:497、src/dev_ng/game/vehicleAi/task/TaskVehicleDeadDriver.h:22、src/dev_ng/game/vehicleAi/task/TaskVehicleShotTire.h:13、src/dev_ng/game/vehicleAi/task/TaskVehicleSpinOut.h:17
动画(副树)车辆动画、敞篷顶、变形为潜艇src/dev_ng/game/vehicleAi/task/TaskVehicleAnimation.h:23-190
玩家驾驶CTaskVehiclePlayerDrive 及各车型子类(输入 → CVehControls)src/dev_ng/game/vehicleAi/task/TaskVehiclePlayer.h:33-477

TaskVehicleGoToAutomobile.h 中的 CTaskVehicleGoToRacing 已被整段注释掉 src/dev_ng/game/vehicleAi/task/TaskVehicleGoToAutomobile.h:32-50。

5.3 CTaskVehicleCruiseNew#

状态:FindRoute → CalculatingRoute → Cruise,以及 StopForJunction、WaitBeforeMovingAgain、GoToStraightLine、GoToNavmesh、GetToRoadUsingNavmesh、Burnout、RevEngine、PauseForUnloadedNodes、Stop;运行标志记录“找不到路线 / 强制重算 / 无法上路” src/dev_ng/game/vehicleAi/task/TaskVehicleCruise.h:181-204。它暴露节点列表、follow route 与路线搜索助手,支持模板路口的路径修正、变道请求 src/dev_ng/game/vehicleAi/task/TaskVehicleCruise.h:239-258。网络同步时只序列化“未来节点”压缩表示:第一个节点地址 32 位 + 两个“链接 5 位/车道 3 位”字节 src/dev_ng/game/vehicleAi/task/TaskVehicleCruise.h:208-282。CTaskVehicleGoToAutomobileNew 继承巡航任务实现定点前往 src/dev_ng/game/vehicleAi/task/TaskVehicleCruise.h:452-455。

5.4 避障与转向:CTaskVehicleGoToPointWithAvoidanceAutomobile#

这是把“目标点”转换为控制输入的底层任务,状态为 GoToPoint、ThreePointTurn、WaitForTraffic、WaitForPed、TemporarilyBrake、Swerve src/dev_ng/game/vehicleAi/task/TaskVehicleGoToAutomobile.h:168-177。关键机制:

  • 障碍收集:车辆、行人、物体、道路边缘四类(eObstructionType),分别由 FindVehicleObstructions/FindPedObstructions/FindObjectObstructions/FindRoadEdgesUsingFollowRoute 填充 AvoidanceTaskObstructionData src/dev_ng/game/vehicleAi/task/TaskVehicleGoToAutomobile.h:229-275、src/dev_ng/game/vehicleAi/task/TaskVehicleGoToAutomobile.h:371-377。
  • 方向打分:对一组候选方向做线段测试(对车辆、圆柱障碍、follow route 道路边界),ScoreAvoidanceDirections 选出最优方向 src/dev_ng/game/vehicleAi/task/TaskVehicleGoToAutomobile.h:363-417。
  • 限速:FindMaximumSpeedForThisCarInTraffic 与按扇区列表为行人/门/其他车减速 src/dev_ng/game/vehicleAi/task/TaskVehicleGoToAutomobile.h:319-347;执法车辆/行人的障碍单独识别 src/dev_ng/game/vehicleAi/task/TaskVehicleGoToAutomobile.h:330-331。
  • 可调参数:跟车距离/速度倍率、行人闪避的速度/距离阈值、危险驾驶判定等 src/dev_ng/game/vehicleAi/task/TaskVehicleGoToAutomobile.h:97-123。
  • 多线程:主计算放在 GoToPointWithAvoidance_OnDeferredTask,superdummy 运动放在 ..._OnDeferredTask_ProcessSuperDummy,两个阶段由 VehicleAvoidanceTask 分两次并行批处理,最后在主线程 OnDeferredTaskCompletion 收尾 src/dev_ng/game/vehicleAi/task/TaskVehicleGoToAutomobile.h:286-288、src/dev_ng/game/vehicleAi/task/DeferredTasks.cpp:208-252。第一批运行期间物理层仍处于“仅主线程更新”状态,第二批(会移动 superdummy)之前才关闭该标志 src/dev_ng/game/vehicleAi/task/DeferredTasks.cpp:221-228。

驾驶员个性 CDriverPersonality 提供能力、激进度、最高巡航速度、绿灯起步延迟、是否闯黄灯/停车标志、跟车距离、变道/打灯习惯等静态查询 src/dev_ng/game/vehicleAi/driverpersonality.h:19-43。

6. 节点列表、路线搜索与 follow route#

6.1 CVehicleNodeList#

固定 CAR_MAX_NUM_PATHNODES_STORED = 12 + 2 个条目:前 2 个是“旧节点”(只为让虚拟路面不跳变而保留),其后是当前与未来节点;每条目含节点地址、链接索引、车道索引,m_targetNodeIndex 标记当前目标 src/dev_ng/game/vehicleAi/VehicleNodeList.h:16-56、src/dev_ng/game/vehicleAi/VehicleNodeList.h:60-140。提供移位、求链接/车道、接入路网 JoinToRoadSystem(默认 60m 拒绝距离)等操作 src/dev_ng/game/vehicleAi/VehicleNodeList.h:105-124、src/dev_ng/game/vehicleAi/pathfind.h:58。

6.2 CPathNodeRouteSearchHelper#

一个 CTaskHelperFSM:Start → FindStartNodesInDirection / FindStartNodesAnyDirection → GenerateWanderRoute 或 Searching → ValidRoute / NoRoute src/dev_ng/game/task/System/TaskHelpers.h:934-956。“漫游”路线由 GenerateWanderRoute_OnUpdate 从已接入路网的节点逐步向前选择后续节点(会参考玩家所在道路,避免车辆在玩家附近打转),不调用 A* src/dev_ng/game/task/System/TaskHelpers.cpp:4869-4930;该文件中唯一的 DoPathSearch 调用位于定点搜索的 Searching 状态(3.3)src/dev_ng/game/task/System/TaskHelpers.cpp:2903、src/dev_ng/game/task/System/TaskHelpers.cpp:2974。

6.3 CVehicleFollowRouteHelper 与 CRoutePoint#

follow route 是节点列表的几何化:最多 MAX_ROUTE_SIZE = 14 个 CRoutePoint,每点含位置+速度(Vec4V)、中央/车道宽度、指定车道、两侧路拱与衰减、两侧车道数、单行道/忽略导航/路口/左转专用/高速/匝道标志、车道中心偏移与节点地址(塞进向量分量)src/dev_ng/game/task/System/TaskHelpers.h:1079-1169、src/dev_ng/game/task/System/TaskHelpers.h:1177-1200。构造来源有四种:节点列表(可选拉线与变道助手)、航点录像、导航网格路线、路点数组 src/dev_ng/game/task/System/TaskHelpers.h:1214-1219。

用途函数证据
目标点与速度FindTargetCoorsAndSpeed(新旧两版实现与“isolated”纯函数版本)src/dev_ng/game/task/System/TaskHelpers.h:1237-1240、src/dev_ng/game/task/System/TaskHelpers.h:1312-1327
superdummy 运动ProcessSuperDummy、CalculatePositionAndOrientationOnVirtualRoad、UpdateTimeslicedInterpolationTargetsrc/dev_ng/game/task/System/TaskHelpers.h:1227-1233、src/dev_ng/game/task/System/TaskHelpers.cpp:10299
dummy 虚拟路面CVirtualRoad::HelperCreateRouteInfoFromFollowRouteAndCenterPossrc/dev_ng/game/Vehicles/Automobile.cpp:8408-8432
物理约束许可SetAllowUseForPhysicalConstraintsrc/dev_ng/game/task/System/TaskHelpers.h:1224-1225

速度在构造时预计算(CalculateDesiredSpeeds),节点的速度档通过 FindSpeedMultiplierWithSpeedFromNodes 映射为 0.5/1.0/1.6/2.2 倍 src/dev_ng/game/task/System/TaskHelpers.h:1218-1219、src/dev_ng/game/vehicleAi/VehicleIntelligence.h:189-200。

7. 路口与交通灯#

7.1 CJunctions / CJunction#

常量值证据
同时活跃路口 JUNCTIONS_MAX_NUMBER360/PS3 60,否则 128src/dev_ng/game/game_config.h:55
每路口车辆 MAX_VEHICLES_AT_JUNCTION64 / 128src/dev_ng/game/game_config.h:52
模板数 / 入口 / 交通灯位置 / 路口节点150 / 16 / 8 / 8src/dev_ng/game/vehicleAi/junctions.h:30-34
每路口相位 / 交通灯实体 / 铁路栏杆 / 铁轨8 / 12 / 8 / 4src/dev_ng/game/vehicleAi/junctions.h:245-263

(junctions.psc 注释中仍写着 JUNCTIONS_MAX_NUMBER 56,与 game_config.h 不一致,以代码为准 src/dev_ng/game/vehicleAi/junctions.psc:4-10。)

CJunctions::Update(注册在 Game Logic 组 src/dev_ng/game/core/game.cpp:2842):以玩家位置加上其地面车辆速度为中心扫描并实例化路口(避免高速接近时交通灯晚出现);联机时用网络同步时间计算时间步;启用时间片时每帧只完整更新 ceil(有车路口数 / 周期) 个路口,长时间未更新的路口也会被补更新 src/dev_ng/game/vehicleAi/junctions.cpp:3874-3960。车辆通过 AddVehicleToJunction/RemoveVehicleFromJunction 登记,路口据此判断冲突路线(VehicleRouteClashesWithOtherCarOnJunction)src/dev_ng/game/vehicleAi/junctions.h:555-557、src/dev_ng/game/vehicleAi/junctions.cpp:1073。路口还管理铁路道口(栏杆升降、道口灯脉冲、扫描接近的火车);按注释与代码,火车接近或栏杆未完全抬起时模板路口对所有入口返回 STOP src/dev_ng/game/vehicleAi/junctions.cpp:2395-2440、src/dev_ng/game/vehicleAi/junctions.cpp:2499-2528、src/dev_ng/game/vehicleAi/junctions.cpp:904-911。

模板数据优先从 JUNCTION_TEMPLATES_PSO_FILE(junctions.pso,忽略校验和)加载,否则读 junctions.xml;加载后补齐到 150 个条目 src/dev_ng/game/vehicleAi/junctions.cpp:4641-4690。模板结构:标志、节点/入口/相位/交通灯位置数、搜索距离、相位偏移、包围盒、节点位置、入口(相位、停止距离、朝向、红灯右转、车道限制、左转滤波相位)、相位时序、交通灯位置;另有“自动路口调整”(位置、周期偏移、周期长度)src/dev_ng/game/vehicleAi/junctions.psc:12-71。__DEV 下有路口编辑器 src/dev_ng/game/vehicleAi/junctions.h:14、src/dev_ng/game/vehicleAi/JunctionEditor.h:6-11。

7.2 两种相位逻辑#

  1. 模板路口(m_iTemplateIndex != -1):CJunction::Update 在本路口的 m_LightTiming 相位间轮转;故障时随机跳相位;单机模式下可跳过无人的行人相位,并按该相位入口的排队车辆数调整时长(空 ×0.5、≤3 辆 ×1.0、≥8 辆 ×2.0、≥14 辆 ×2.5),联机时不做自适应以保持各机一致 src/dev_ng/game/vehicleAi/junctions.cpp:318-420、src/dev_ng/game/vehicleAi/junctions.cpp:122-128。GetTrafficLightCommand 返回 STOP/AMBER/GO/左右转滤波/行人等命令 src/dev_ng/game/vehicleAi/junctions.cpp:890-922、src/dev_ng/game/vehicleAi/junctions.h:38-49。
  2. 节点交通灯(SPECIAL_TRAFFIC_LIGHT 节点):CTrafficLights::CalculateNodeLightCycle 根据进入路口方向的主轴(|x|>|y| → 周期 1,否则周期 2)分配相位 src/dev_ng/game/control/trafficlights.cpp:196-269;灯色完全由网络同步时间(加路口自动调整的偏移/缩放)对周期长度取模得到:周期 = 长绿 10s + 短绿 10s + 2×黄 2.5s = 25s,带行人相位时再加 15s 行人与一个黄灯 = 42.5s src/dev_ng/game/control/trafficlights.cpp:453-503、src/dev_ng/game/control/trafficlights.h:80-85。注释中的时间表自称“THIS IS WRONG” src/dev_ng/game/control/trafficlights.cpp:463-468。

ShouldCarStopForLightNode 的判定:忽略本路口的出口灯与不属于当前路口的灯;红灯必停,黄灯由 CDriverPersonality::RunsAmberLights 决定;允许已越线车辆(不超过 1 个车长,大车 0.5 个)继续通过;检查过一组灯后不再检查下一组,以免连续两组灯卡住车辆 src/dev_ng/game/control/trafficlights.cpp:294-451。

7.3 CTrafficLights 的其他职责#

  • 每帧仅更新“交通灯地面光照亮度”:20 点后全亮、19–20 点渐亮、6 点后熄灭、5–6 点渐暗,并取湿度/雾/雨的最大值 src/dev_ng/game/control/trafficlights.cpp:154-188。
  • 交通灯模型(MODEL_ATTRIBUTE_IS_TRAFFIC_LIGHT)实体通过扩展 TrafficLightInfos(池大小来自配置)记录所属路口、灯索引、入口/车道链接(最多 8)、已损坏灯色位掩码与缓存的骨骼矩阵 src/dev_ng/game/control/trafficlights.h:175-330、src/dev_ng/game/control/trafficlights.cpp:63;RenderLights/RenderPedLights 负责灯与 corona 的渲染 src/dev_ng/game/control/trafficlights.h:145-150。

8. 车辆录像:CVehicleRecordingMgr#

方面实现证据
数据格式CVehicleRecording : pgBase 是 CVehicleStateEachFrame 数组:时间戳、速度(s16,最高 120 m/s)、矩阵 A/B 轴(s8)、转向/油门/刹车/手刹(s8)、位置(float)src/dev_ng/rage/framework/src/fwcontrol/record.h:4-54、src/dev_ng/rage/framework/src/fwcontrol/record.h:67-100
容量同时录制 / 回放各 24 辆;录制缓冲 480000 字节(约 40 分钟),每 125ms 记录一帧,每 10s 刷盘src/dev_ng/rage/framework/src/fwcontrol/record.h:56-57、src/dev_ng/game/control/record.h:37-53
流式录像文件作为流式模块注册(启动时 RegisterStreamingModule),CVehicleRecordingStreaming 管理引用计数与 Place/Removesrc/dev_ng/game/core/game.cpp:579、src/dev_ng/game/control/record.h:63-105
回放StartPlaybackRecordedCar(车, 索引, 是否用 AI, 速度, 驾驶标志, 循环, …, 标志, AI 恢复延迟);每槽维护附加旋转、局部/全局偏移、运行时间、速度、暂停、AI 模式等src/dev_ng/game/control/record.h:241、src/dev_ng/game/control/record.h:358-381
推进RetrieveDataForThisFrame 对 24 个槽逐个 UpdatePlaybackForVehicleRecording;sm_bUpdateWithPhysics 时在每个物理时间片推进(时间步按时间片数均分,仍以游戏毫秒计时以免与脚本计时漂移),否则在 CGameWorld::Process 物理之后推进src/dev_ng/game/control/record.cpp:1849-1882、src/dev_ng/game/physics/physics.cpp:1383-1388、src/dev_ng/game/scene/world/GameWorld.cpp:2094-2105
驱动车辆插值帧间状态后 SetMatrix + HandleRecordingTeleport,设置线速度与角速度src/dev_ng/game/control/record.cpp:2312-2383
AI 混合ChangeCarPlaybackToUseAI 让录像车改由 AI 驾驶并可在之后恢复全录像;FinishAiUpdate 与 CVehicleIntelligence::Process 对“不使用 AI 的录像”走简化路径src/dev_ng/game/control/record.cpp:1655、src/dev_ng/game/control/record.cpp:2790、src/dev_ng/game/Vehicles/Vehicle.cpp:29876-29880、src/dev_ng/game/vehicleAi/VehicleIntelligence.cpp:1065-1081
物理交互录像车可在物理层非激活状态回放;ProcessPostPhysics 处理切换 AI 与非激活src/dev_ng/game/Vehicles/Vehicle.cpp:2079-2090、src/dev_ng/game/Vehicles/Automobile.cpp:3531-3533
录制非 __FINAL 构建每帧 SaveDataForThisFramesrc/dev_ng/game/scene/world/GameWorld.cpp:2096-2098

9. 航点录像与路线池#

  • fwWaypointRecordingRoute : pgBase:每个航点 = 位置 + 打包(标志 16 位、朝向 8 位、移动混合比 8 位)+ 左右可用空间;标志含跳跃、着陆、滑雪翻转、下落、不可打断、出水、车辆、施加跳跃力;最多 512 个航点 src/dev_ng/rage/framework/src/fwcontrol/WaypointRecordingRoute.h:12-50、src/dev_ng/rage/framework/src/fwcontrol/WaypointRecordingRoute.h:88-107。
  • CWaypointRecording 作为流式模块(CWaypointRecordingStreamingInterface)供脚本请求/引用计数,__BANK 下可录制与编辑(步行、滑雪、车内分别有采样间距参数)src/dev_ng/game/control/WaypointRecording.h:56-188、src/dev_ng/game/core/game.cpp:578;游戏版 CWaypointRecordingRoute 只在 __BANK 下增加编辑函数 src/dev_ng/game/control/WaypointRecordingRoute.h:1-20。车辆跟随航点录像时由 CVehicleFollowRouteHelper::ConstructFromWaypointRecording 转成 follow route src/dev_ng/game/task/System/TaskHelpers.h:1215。
  • Route.h 的 CPointRoute(最多 8 点,池 40、spillover 0.66)与 CPatrolRoute(每点附带动画描述,池 6)是 ped 路线的小型池化容器 src/dev_ng/game/control/Route.h:93-118、src/dev_ng/game/control/Route.h:297-328、src/dev_ng/game/control/Route.cpp:4-5。

10. GPS:CGps#

GPS 有 3 个槽:航点、雷达标记、离散路线(后者不播报);雷达标记槽同时承载赛道、多点航点与自定义路线 src/dev_ng/game/vehicleAi/pathfind.h:40-44、src/dev_ng/game/control/gps.h:26-29、src/dev_ng/game/control/gps.cpp:2426-2427。每槽存储节点坐标(因为路网节点可能被流出)、地址、节点信息与到终点距离,容量来自配置池 CGpsNumNodesStored src/dev_ng/game/control/gps.h:174-177、src/dev_ng/game/control/gps.cpp:2322。

方面实现证据
状态机OFF;计算中(普通/静默/赛道/多点);工作中(普通/赛道/多点/自定义)src/dev_ng/game/control/gps.h:81-98
计算向 ThePaths 申请包围起终点的节点区域(MakeRequestForNodesToBeLoaded),区域就绪且本帧异步搜索未被占用时调用 GenerateRoutePointsForGps(..., async=true);返回负值表示异步搜索刚启动src/dev_ng/game/control/gps.cpp:391-468
GPS 标志忽略单行、遵守交规、避高速、不平移路线、自定义接近距离、避越野、忽略终点 Z 等src/dev_ng/game/vehicleAi/pathfind.h:153-163
推进UpdateRoute:按最近线段 ShiftRoute 截掉已走过的部分,并定期重绘src/dev_ng/game/control/gps.cpp:941-986
指令与语音CalcRouteInstruction 把路网方向转换为左转/右转/靠左/靠右/直行/掉头等指令并播报src/dev_ng/game/control/gps.h:100-114、src/dev_ng/game/control/gps.cpp:1745-1794
每帧CGps::Update 更新各槽、释放未使用的异步搜索槽src/dev_ng/game/control/gps.cpp:2367-2441、src/dev_ng/game/core/game.cpp:2837

11. 其他车辆 AI 组件#

组件作用证据
CFlyingVehicleAvoidanceManager飞机/直升机之间的转向避让(每帧在人口组更新)src/dev_ng/game/vehicleAi/FlyingVehicleAvoidance.h:15-77、src/dev_ng/game/core/game.cpp:2793
CRoadSpeedZone地图上让车辆减速的区域(最高速度)src/dev_ng/game/vehicleAi/roadspeedzone.h:1-31
CPathZone / CPathZoneMapping最多 4 个路径区域及其互相映射(MAX_NUM_PATHZONES = 4)src/dev_ng/game/vehicleAi/pathzones.h:10-60
VehicleNavigationHelper不用导航网格/路网时绕地形与物体导航的静态检查src/dev_ng/game/vehicleAi/VehicleNavigationHelper.h:10-14
racingline.*赛车线(TDeque 节点容器等)src/dev_ng/game/vehicleAi/racingline.h:1-30

12. 线程与平台差异#

条件影响证据
!__PS3CVehicleIntelligence 收尾与车辆插值走延迟多线程任务src/dev_ng/game/vehicleAi/VehicleIntelligence.cpp:1109-1125
延迟任务期间打开 fwRegdRef/事件/环境组/空间数组锁,联机时允许其他线程访问网络管理器,禁止任务删除src/dev_ng/game/vehicleAi/task/DeferredTasks.cpp:140-154
__PS3异步最近节点搜索作为 SPU 任务运行(区域指针表 DMA、180KB scratch)src/dev_ng/game/vehicleAi/pathfind.cpp:7684-7703
XENON_OR_PS3路口/交通灯/生成链接容量减小src/dev_ng/game/game_config.h:51-55
RSG_ORBIS || RSG_PC || RSG_DURANGOFindStreetNameAtPositionsrc/dev_ng/game/vehicleAi/pathfind.cpp:10581-10587
__BANK / __DEV路径搜索历史、路网调试绘制(PATHSEARCHDRAW)、路口编辑器、航点录制src/dev_ng/game/vehicleAi/pathfind.h:326-330、src/dev_ng/game/vehicleAi/pathfind.cpp:79、src/dev_ng/game/vehicleAi/junctions.h:14、src/dev_ng/game/scene/world/GameWorld.cpp:2107-2110

13. 约束与边界行为#

  • 节点指针只在区域加载时有效:FindNodePointer 断言区域已加载;安全版本在空地址、区域未加载或索引越界时返回 NULL src/dev_ng/game/vehicleAi/pathfind.h:798-845。CVehicleNodeList::GetPathNode 同样检查区域是否加载 src/dev_ng/game/vehicleAi/VehicleNodeList.h:64-71。GPS 因此单独缓存坐标。
  • 搜索状态写在共享节点上:DoPathSearch 把临时代价写入 CPathNode::m_distanceToTarget 并依赖“清理列表”复位,所以它不是可重入的,必须在主线程串行调用(推断,依据实现方式;异步 GPS 搜索使用独立的 SPU/任务版本)src/dev_ng/game/vehicleAi/pathfind.cpp:1206-1228。
  • 网络:克隆车辆不运行任务 AI(4.2);交通灯与路口时间基于网络同步时间,模板路口在联机时不自适应 src/dev_ng/game/control/trafficlights.cpp:453-461、src/dev_ng/game/vehicleAi/junctions.cpp:3910-3923。
  • dummy 安全阀:没有 follow route 的 dummy 车会被强制转回 real 或停用物理(4.2)。

14. 未决问题与证据不足#

  • 未找到路网区域资源(nodes*.ynd)与 junctions.xml/pso 数据本体,无法给出具体节点数量或模板内容。
  • TaskVehicleGoToAutomobile.cpp(约 49 万字节)与 TaskVehicleCruise.cpp 的完整控制律(转向 PID、刹车距离曲线、变道条件)只按结构描述;CVehPIDController 的使用点未追踪。
  • GenerateRoutePointsForGps 的异步执行细节、PathfindNodeSearchJob.cpp 中 CPathFindGPSSpu 的实现未展开。
  • CJunction::Deploy(模板绑定与入口推断)与 ScanAndInstanceJunctionsNearOrigin 的扫描半径未展开。