车辆物理、操控、损坏与 LOD
本页解释车辆“怎么动、怎么坏、怎么省”:CHandlingData(handling.meta)的结构、子 handling 类型与单位换算;车辆在每个物理时间片中 ProcessPhysics → ProcessPhysics2 → ProcessPhysics3 的多遍协议;CWheel 的接触获取、悬挂与轮胎摩擦模型,以及在工作线程上运行的 RK4 轮子积分器;CTransmission 的档位与引擎模型;空气阻力、飞行器与水上车辆的分支;CVehicleDamage/CVehicleDeformation 的健康值与形变纹理(含各平台 GPU/CPU/EDGE 路径);最后是 real / dummy / superdummy / 时间片四级 LOD 的决策与转换。
父页面与对象模型见 vehicle-architecture.md;dummy 车辆依赖的路网与 follow route 见 vehicle-ai-and-road-network.md。
背景与相关页面#
- RAGE 物理(
phInst/phCollider/articulated body/碰撞迭代器)与CPhysics::Update的时间片调度:见 ../09-physics/rage-physics-engine.md、../09-physics/game-physics-and-ragdoll.md。浮力CBuoyancy的细节也归该处,本页只说明车辆如何调用。 - fragment(车辆部件可断裂)与车窗玻璃:见 ../09-physics/fragments-cloth-glass-rope.md、../12-vfx/decals-and-vfx-systems.md。
- 车辆形变在 GPU 侧的绘制(
CApplyDamage)与车辆着色器:见 ../11-rendering/render-pipeline-and-phases.md、../11-rendering/shaders-and-materials.md。 - 线程与
sysDependency:见 ../01-runtime/threading-and-render-thread.md。
相关源码文件#
| 文件 | 作用 |
|---|---|
game/Vehicles/handlingMgr.h、handlingMgr.cpp、Metadata/HandlingInfo.psc | CHandlingData、子 handling、标志枚举、CHandlingDataMgr 加载与单位换算 |
game/Vehicles/Metadata/AIHandlingInfo.* | AI 刹车/弯道速度曲线 CAIHandlingInfo |
game/Vehicles/wheel.h、wheel.cpp、WheelRendering.cpp、wheelspu.job | CWheel、CWheelIntegrator(含 PS3 SPU 版本) |
game/Vehicles/Transmission.h、Transmission.cpp | CTransmission |
game/Vehicles/Automobile.cpp、Vehicle.cpp | ProcessPhysics 系列、ProcessProbes、空气阻力、LOD 转换 |
game/Vehicles/virtualroad.h/.cpp | dummy 车辆的“虚拟路面”采样 |
game/Vehicles/vehicleDamage.h/.cpp、VehicleDamage.psc、game/shader_source/Vehicles/vehicle_common_values.h | 损坏、形变纹理与平台常量 |
game/Vehicles/Heli.cpp、Planes.cpp、boat.cpp、Submarine.cpp、train.cpp、LandingGear.*、Propeller.*、AnchorHelper.* | 各载具专属物理 |
game/vehicleAi/VehicleAILod.*、VehicleAILodManager.* | LOD 标志与管理器 |
game/physics/physics.cpp | PreSimUpdate 多遍调度、GPU 损坏队列 |
1. 一个物理时间片内的车辆#
CPhysics::PreSimUpdate 在每个物理时间片对场景更新列表 SU_PRESIM_PHYSICS_UPDATE 执行 ProcessPhysics;返回 PHYSICS_POSTPONE 的实体(停在其他物理体上的车)在第二轮补跑;返回 PHYSICS_NEED_SECOND_PASS 的(“等待 SPU 轮子积分器的车辆”)在所有实体第一遍之后调用 ProcessPhysics2;返回 PHYSICS_NEED_THIRD_PASS 的(“把轮子力施加到其他车辆上”)再调用 ProcessPhysics3;网络克隆的 net blender 更新穿插在这些遍之间 src/dev_ng/game/physics/physics.cpp:1374-1510、src/dev_ng/game/scene/Physical.h:73-74。录像回放也可选择在每个物理时间片内、PreSim 之前推进 src/dev_ng/game/physics/physics.cpp:1383-1388。
证据:superdummy 早退 src/dev_ng/game/Vehicles/Automobile.cpp:3220-3227;调用基类与延后 src/dev_ng/game/Vehicles/Automobile.cpp:3235-3238、src/dev_ng/game/Vehicles/Automobile.cpp:3313-3323、src/dev_ng/game/Vehicles/Vehicle.cpp:20086-20090;变速箱 src/dev_ng/game/Vehicles/Automobile.cpp:3340-3452;门 src/dev_ng/game/Vehicles/Automobile.cpp:3454-3470;睡眠分支 src/dev_ng/game/Vehicles/Automobile.cpp:3472-3535;飞行与稳定性 src/dev_ng/game/Vehicles/Automobile.cpp:3625-3632;每轮输入 src/dev_ng/game/Vehicles/Automobile.cpp:3931-4060;探测 src/dev_ng/game/Vehicles/Automobile.cpp:4193-4221;启动积分并请求第二遍 src/dev_ng/game/Vehicles/Automobile.cpp:4226-4242;第二遍 src/dev_ng/game/Vehicles/Automobile.cpp:4748-4912;第三遍 src/dev_ng/game/Vehicles/Automobile.cpp:4915-4933。
2. 操控数据:CHandlingData#
2.1 结构#
CHandlingData 是按名字(m_handlingName)索引、所有同型车辆共享的只读参数块;车辆实例只持有指针 pHandling src/dev_ng/game/Vehicles/handlingMgr.h:851-870、src/dev_ng/game/Vehicles/vehicle.h:2583。主要字段分组:
| 组 | 字段(节选) | 证据 |
|---|---|---|
| 车身 | m_fMass、m_fInitialDragCoeff、m_fDownforceModifier、m_vecCentreOfMassOffset、m_vecInertiaMultiplier、m_fPercentSubmerged → m_fBuoyancyConstant | src/dev_ng/game/Vehicles/handlingMgr.h:871-882 |
| 传动 | m_fDriveBiasFront/Rear、m_nInitialDriveGears、m_fDriveInertia、离合换挡速率、m_fInitialDriveForce、m_fInitialDriveMaxVel/MaxFlatVel | src/dev_ng/game/Vehicles/handlingMgr.h:884-897 |
| 制动/转向 | m_fBrakeForce、m_fBrakeBiasFront/Rear、m_fHandBrakeForce、m_fSteeringLock(Inv) | src/dev_ng/game/Vehicles/handlingMgr.h:899-907 |
| 轮胎 | m_fTractionCurveMax/Min/Lateral(含预计算倒数)、m_fTractionSpringDeltaMax、m_fLowSpeedTractionLossMult、m_fCamberStiffnesss、m_fTractionBiasFront/Rear、m_fTractionLossMult | src/dev_ng/game/Vehicles/handlingMgr.h:909-930 |
| 悬挂 | m_fSuspensionForce、CompDamp、ReboundDamp、上下限、Raise、前后偏置、防倾杆力与偏置、侧倾中心高度 | src/dev_ng/game/Vehicles/handlingMgr.h:933-950 |
| 杂项 | 碰撞/武器/形变/引擎伤害倍率、油箱与机油容积、油耗、座位偏移、售价、火箭推进容量与助推极速 | src/dev_ng/game/Vehicles/handlingMgr.h:952-968 |
| 标志 | mFlags(模型)、hFlags(操控)、dFlags(门损坏),由 meta 中十六进制字符串解析 | src/dev_ng/game/Vehicles/handlingMgr.h:970-978 |
| AI | m_AIHandling 名 → CAIHandlingInfo* | src/dev_ng/game/Vehicles/handlingMgr.h:980-991 |
| 子 handling | atArray<CBaseSubHandlingData*> m_SubHandlingData | src/dev_ng/game/Vehicles/handlingMgr.h:1060 |
前后偏置通过 Selectf(fFrontRearSelector, front, rear) 取值,轮子按自身前/后选择器读取 src/dev_ng/game/Vehicles/handlingMgr.h:1005-1011。
2.2 子 handling 类型#
GetXxxHandlingData() 线性扫描 m_SubHandlingData 按 GetHandlingType() 查找,没有则返回 NULL src/dev_ng/game/Vehicles/handlingMgr.cpp:1362-1373、src/dev_ng/game/Vehicles/handlingMgr.h:1035-1057。类型枚举 src/dev_ng/game/Vehicles/handlingMgr.h:204-219:
| 类型 | 类 | 典型字段 | 证据 |
|---|---|---|---|
HANDLING_TYPE_BIKE | CBikeHandlingData | 前后倾质心/力、最大侧倾角、翘头/翘尾平衡点、空中转向、跳跃力 | src/dev_ng/game/Vehicles/Metadata/HandlingInfo.psc:257-278 |
FLYING / VERTICAL_FLYING | CFlyingHandlingData | 推力与衰减、推力矢量、偏航/横滚/俯仰倍率与稳定、形状/攻角升力、起落架阻力、风、湍流、引擎关闭滑翔 | src/dev_ng/game/Vehicles/Metadata/HandlingInfo.psc:160-204 |
BOAT | CBoatHandlingData | 船体盒倍率等 | src/dev_ng/game/Vehicles/Metadata/HandlingInfo.psc:99-130 |
SEAPLANE | CSeaPlaneHandlingData | 水上飞机浮筒参数 | src/dev_ng/game/Vehicles/Metadata/HandlingInfo.psc:132-144 |
SUBMARINE | CSubmarineHandlingData | 俯仰/偏航/横滚、下潜速度、转向与移动阻力 | src/dev_ng/game/Vehicles/Metadata/HandlingInfo.psc:280-290 |
TRAILER | CTrailerHandlingData | 挂接限位(俯仰/横滚/偏航)、扶正弹簧/阻尼、挂接最大距离/穿透、位置约束质量比 | src/dev_ng/game/Vehicles/Metadata/HandlingInfo.psc:292-302 |
CAR | CCarHandlingData | 后部弹起冲量、前后束/外倾/主销后倾、引擎阻力、最大驱动偏置转移、跳跃力缩放、m_strAdvancedFlags(CF_*)、m_AdvancedData | src/dev_ng/game/Vehicles/Metadata/HandlingInfo.psc:304-321 |
WEAPON | CVehicleWeaponHandlingData | 6 个武器哈希/座位/改装类型、12 个炮塔速度与俯仰限制 | src/dev_ng/game/Vehicles/Metadata/HandlingInfo.psc:206-246 |
SPECIAL_FLIGHT | CSpecialFlightHandlingData | 角/线阻尼、升力系数、临界升力角等(悬浮/飞行模式车辆) | src/dev_ng/game/Vehicles/Metadata/HandlingInfo.psc:323-354 |
2.3 标志位#
| 位集 | 作用 | 示例 | 证据 |
|---|---|---|---|
VehModelFlags(mFlags) | 车型结构/外形 | MF_IS_VAN/BUS/LOW/BIG、ABS 选项、MF_HAS_TRACKS、轴类型、MF_NO_WHEEL_BURST、MF_INDESTRUCTIBLE、MF_IS_RC | src/dev_ng/game/Vehicles/handlingMgr.h:41-82 |
VehHandlingFlags(hFlags) | 操控行为 | HF_HAS_RALLY_TYRES、HF_STEER_REARWHEELS、HF_CVT、越野重力 HF_OFFROAD_ABILITIES(_X2)、HF_ENABLE_LEAN、HF_ARMOURED | src/dev_ng/game/Vehicles/handlingMgr.h:84-127 |
CarAdvancedFlags(CCarHandlingData::aFlags) | 新一代汽车选项 | 差速器类型、变速箱类型、CF_HARD_REV_LIMIT、CF_ALLOW_TURN_ON_SPOT、CF_FIX_OLD_BUGS、CF_USE_DOWNFORCE_BIAS、CF_ALLOWS_EXTENDED_MODS | src/dev_ng/game/Vehicles/handlingMgr.h:140-186 |
SpecialFlightModeFlags | 特殊飞行 | 倒飞可用、不收轮、按速度减阻、维持悬停高度 | src/dev_ng/game/Vehicles/handlingMgr.h:188-201 |
CF_FIX_OLD_BUGS 是一个兼容开关:轮子积分与悬挂中多处以它在“旧行为”和“修正后行为”之间选择(例如静态力推导方式),旧车型的手感因此保持不变 src/dev_ng/game/Vehicles/wheel.cpp:7865-7887、src/dev_ng/game/Vehicles/wheel.cpp:3502-3522。
2.4 加载、单位换算与覆盖规则#
| 步骤 | 实现 | 证据 |
|---|---|---|
| 注册挂载 | CHandlingDataMgr::Init() 为 HANDLING_FILE 与 VEHICLEEXTRAS_FILE 注册挂载接口(由 CVehicle::InitSystem 调用) | src/dev_ng/game/Vehicles/handlingMgr.cpp:1843-1853、src/dev_ng/game/Vehicles/Vehicle.cpp:1105-1108 |
| 地图前初始化 | Init(INIT_BEFORE_MAP_LOADED):AI handling 初始化、CHandlingData::InitPool、LoadHandlingData(从最后一个文件向前遍历) | src/dev_ng/game/Vehicles/handlingMgr.cpp:1923-1936、src/dev_ng/game/Vehicles/handlingMgr.cpp:1879-1904 |
| 地图后初始化 | 载入车辆附加文件(上车点)、更新车辆类别信息 | src/dev_ng/game/Vehicles/handlingMgr.cpp:1937-1946 |
| 解析 | PARSER.LoadObject 到单例后整体 ConvertToGameUnits(true) | src/dev_ng/game/Vehicles/handlingMgr.cpp:2026-2035 |
| DLC 追加 | AppendHandlingMetaData:解析到临时管理器,同名已存在则丢弃新条目(先到先得,不覆盖) | src/dev_ng/game/Vehicles/handlingMgr.cpp:337-358、src/dev_ng/game/Vehicles/handlingMgr.cpp:2037-2077 |
| 池 | 所有 handling 对象共用 CHandlingObject 基类池,元素大小取最大子类 | src/dev_ng/game/Vehicles/handlingMgr.cpp:1809-1829 |
CHandlingData::ConvertToGameUnits src/dev_ng/game/Vehicles/handlingMgr.cpp:1640-1754 中值得注意的换算:
- 驱动偏置:前驱比例 <0.1 视为纯后驱、>0.9 视为纯前驱,否则前后各乘 2(使平均为 1);刹车、牵引、悬挂、防倾杆偏置同样“后 = 1 − 前,再各乘 2”
src/dev_ng/game/Vehicles/handlingMgr.cpp:1652-1696。 - 浮力常数
100 / m_fPercentSubmerged;横向牵引曲线与转向锁角从度转弧度;m_fTractionCurveMax <= Min时告警并用LARGE_FLOAT兜底src/dev_ng/game/Vehicles/handlingMgr.cpp:1702-1734、src/dev_ng/game/Vehicles/handlingMgr.cpp:1751-1752。 - 阻尼 ×0.1、阻力 ×0.0001;最大平地速度 km/h → m/s,
m_fInitialDriveMaxVel = 1.2 × MaxFlatVel(为档位间距留 20% 余量);档位数截断到MAX_NUM_GEARS = 10src/dev_ng/game/Vehicles/handlingMgr.cpp:1736-1749、src/dev_ng/game/Vehicles/Transmission.h:24。 - 找不到 AI handling 时回落到
AVERAGEsrc/dev_ng/game/Vehicles/handlingMgr.cpp:1642-1650。
2.5 AI handling#
CAIHandlingInfo 给 AI 驾驶提供最小/最大刹车距离、刹车距离处最高速度、绝对最低速度,以及“弯角 → 速度”曲线点 m_AICurvePoints src/dev_ng/game/Vehicles/Metadata/AIHandlingInfo.psc:4-24。运行期可被覆盖,例如 Speedo 车型在联机时改用 TRUCK 曲线 src/dev_ng/game/Vehicles/Vehicle.cpp:5039-5061。
3. 通用物理入口#
3.1 CVehicle::ProcessPhysics#
基类版本 src/dev_ng/game/Vehicles/Vehicle.cpp:20073-20368 处理所有车辆共享的“附加力”:superdummy 直接返回;有 m_pGroundPhysical 且允许延后时返回 POSTPONE;脚本最高速度钳制(施加反向力并告警);超级刹车;竞技场模式垂直阻尼;冲坡车额外重力;侧向冲撞;水上载具在接近水面时重新激活;方向盘骨骼旋转(第一人称时使用运动任务的方向盘角);地面参考系速度(站在火车/船/飞机上时禁止睡眠);火箭推进、通用助推、滑翔/特殊飞行、外伸支腿、跳跃与“蓄力跳” src/dev_ng/game/Vehicles/Vehicle.cpp:20081-20090、src/dev_ng/game/Vehicles/Vehicle.cpp:20114-20136、src/dev_ng/game/Vehicles/Vehicle.cpp:20202-20235、src/dev_ng/game/Vehicles/Vehicle.cpp:20284-20332、src/dev_ng/game/Vehicles/Vehicle.cpp:20334-20361。
3.2 ProcessPrePhysics / ProcessPostPhysics / 睡眠#
ProcessPrePhysics:(frag 优化下)为非 superdummy 车补发或释放 fragment 缓存条目,处理喷气尾流,调用各 gadget 的ProcessPrePhysicssrc/dev_ng/game/Vehicles/Vehicle.cpp:1766-1791。ProcessPostPhysics:非静止的 superdummy 尝试失活;real 车缓存当前速度供 superdummy 使用;只有“停放且静止”的车才可成为停放 superdummy;录像车在需要时切到 AI 回放src/dev_ng/game/Vehicles/Vehicle.cpp:2056-2090。ProcessIsAsleep:无 frag 缓存/不在物理层/被固定/基础附着视为睡眠;否则若 collider 睡眠但ForceNoSleep()要求清醒则重置睡眠src/dev_ng/game/Vehicles/Vehicle.cpp:11590-11631。睡眠时CAutomobile跳过积分,只给轮子ProcessAsleep,录像/过场车在物理层非激活时仍做探测src/dev_ng/game/Vehicles/Automobile.cpp:3472-3535。CVehicleAILodManager::ms_bDeTimesliceTransmissionAndSleep为真时,变速箱与睡眠逻辑只在第 0 个时间片用整帧步长运行src/dev_ng/game/Vehicles/Automobile.cpp:3346-3360、src/dev_ng/game/Vehicles/Automobile.cpp:3474-3486、src/dev_ng/game/vehicleAi/VehicleAILodManager.cpp:62。
4. 轮子:CWheel#
4.1 状态与配置#
CWheel 把“每帧变化的动态标志”与“构造后基本不变的配置标志”分开:动态标志含接触(WF_HIT/HIT_PREV)、作弊(TC/SC/抓地)、烧胎、浅/深水、ABS 状态与模式、压人、降抓地、重置、断轮、dummy 过渡、人行道、睡在碎片上等 src/dev_ng/game/Vehicles/wheel.h:72-125;配置标志含摩托/左右/后轮、转向/驱动、独立/整体悬挂、实例化渲染、高摩擦、履带、飞机轮、两栖轮、三轮车中心轮等 src/dev_ng/game/Vehicles/wheel.h:127-157。液压悬挂有独立的状态机 eWheelHydraulicState(锁定、单/全轮弹跳、着陆、自由)src/dev_ng/game/Vehicles/wheel.h:159-193。轮胎/悬挂健康默认 1000,轮胎 ≤350 视为瘪胎,850/450 为抓地分档阈值 src/dev_ng/game/Vehicles/wheel.h:205-213。
4.2 接触获取:真实车 vs dummy#
CAutomobile::ProcessProbes 决定轮子接触来源 src/dev_ng/game/Vehicles/Automobile.cpp:8287-8460:
- real 车且轮子是 frag 子件:不发射线;轮子接触来自物理碰撞阶段——
CVehicle::ProcessPreComputeImpacts遍历碰撞点,对每个轮子调用CWheel::ProcessImpact选出最佳接触,ProcessProbes里只做ProcessImpactResultssrc/dev_ng/game/Vehicles/Automobile.cpp:8302-8310、src/dev_ng/game/Vehicles/Vehicle.cpp:20508-20541、src/dev_ng/game/Vehicles/Vehicle.cpp:22158、src/dev_ng/game/Vehicles/wheel.cpp:1279-1300。ProcessImpact会忽略推挤前一轮与车辆的接触,以免车辆互相开到对方身上src/dev_ng/game/Vehicles/wheel.cpp:1291-1300。 - AI 驾驶的飞行器高于高度图最大值:直接重置轮子,跳过探测
src/dev_ng/game/Vehicles/Automobile.cpp:8312-8327。 - dummy 车:不与真实几何体做探测,而是把每个轮子的探测线段与“虚拟路面”求交。虚拟路面由 follow route(拖车用牵引车的)构造
CVirtualRoad::TRouteInfo(三点两段、车道宽度、路拱、路口高度图),长车(>9m)或路口处用前后两个中心分别采样;没有 follow route 时退回节点列表并断言src/dev_ng/game/Vehicles/Automobile.cpp:8360-8460、src/dev_ng/game/Vehicles/virtualroad.h:21-80。随后HandleDummyProbesBottomingOut与UpdateDummyConstraints把车约束在路面范围内。
4.3 轮子积分器(RK4,工作线程)#
CAutomobile::StartWheelIntegratorTask:直升机仅在有轮子接触时才跑完整积分;跑积分时关闭 collider 自身重力(重力在积分器内施加,APPLY_GRAVITY_IN_INTEGRATOR = 1),否则恢复重力并直接施加内部力/力矩 src/dev_ng/game/Vehicles/Automobile.cpp:4713-4744、src/dev_ng/game/Vehicles/wheel.h:53。
CWheelIntegrator::ProcessIntegration 在 articulated 车上先确保速度完全传播(使任务不需要关节数据),然后把 RunFromDependency 作为高优先级 sysDependency 插入调度器并递增 jobPending;ProcessPhysics2 中的 ProcessResult 自旋等待其归零 src/dev_ng/game/Vehicles/wheel.cpp:7893-7927、src/dev_ng/game/Vehicles/wheel.cpp:7941-7958、src/dev_ng/game/Vehicles/Automobile.cpp:4754-4766。PS3 上有 SPU 版本(SPU_WHEEL_INTEGRATION,wheelspu.job 把 wheel.h、articulated body、bound 等源码直接编进 SPU 作业)src/dev_ng/game/Vehicles/wheel.h:51、src/dev_ng/game/Vehicles/wheelspu.job:1-37。
ProcessIntegrationTask src/dev_ng/game/Vehicles/wheel.cpp:7744-7891:
- 把内部力/力矩转成加速度/角加速度(力矩先变换到局部乘逆惯量再变回)
src/dev_ng/game/Vehicles/wheel.cpp:7755-7760。 - 子步数
nNumLoops = max(1, floor(dt × 60 + 1)),dt_sub = dt / nNumLoops——以 60Hz 为目标步长src/dev_ng/game/Vehicles/wheel.cpp:7762-7769。 - 每轮初始化滑移状态;刚被重置且悬空的轮子把其静态力折算进重力项(处理重置当帧接触未计算的情况)
src/dev_ng/game/Vehicles/wheel.cpp:7787-7826。 - 每个子步做四阶 Runge-Kutta:
WheelIntegrationEvaluate求 a/b/c/d 四个导数(含车体速度、角速度、加速度、每轮角滑移变化率与轮力),按 1/6(a+2b+2c+d) 合成并推进矩阵、速度、角速度,同时把每轮力做跨子步平均src/dev_ng/game/Vehicles/wheel.cpp:7835-7888。 ProcessResultInternal写出结果src/dev_ng/game/Vehicles/wheel.cpp:7890。
第三遍 IntegrationFinalProcess 把轮子求得的力反向施加到轮下的物理体(如被压的车),并按对方质量做速度变化上限 src/dev_ng/game/Vehicles/wheel.cpp:4695-4716、src/dev_ng/game/Vehicles/Automobile.cpp:4915-4925。
4.4 悬挂模型#
CWheel::IntegrateSuspensionAccel src/dev_ng/game/Vehicles/wheel.cpp:3383-3570:
- 压缩速度来自本帧与上一帧压缩量差(按探测步长归一,并按悬挂长度或地面物理体钳制)
src/dev_ng/game/Vehicles/wheel.cpp:3414-3419。 - 防倾杆力 =
AntiRollBarForce × 前后偏置 × 质量 × g × (对侧压缩 − 本侧压缩)src/dev_ng/game/Vehicles/wheel.cpp:3430-3435。 - 弹簧刚度
m_fSuspensionForce × 健康/改装系数 × 前后偏置 × 限位块系数;CF_FIX_OLD_BUGS车型改为“静态压缩前按静态力线性、之后按刚度增加”的分段模型src/dev_ng/game/Vehicles/wheel.cpp:3500-3522。 - 阻尼:回弹为线性
v × ReboundDamp,压缩为sqrt(v) × CompDamp(飞机轮除外,避免不平衡悬挂抖动)src/dev_ng/game/Vehicles/wheel.cpp:3553-3566。 - 液压着陆时弹簧/阻尼按调参放大/缩小,超限会扣悬挂健康
src/dev_ng/game/Vehicles/wheel.cpp:3524-3559。
4.5 轮胎摩擦模型#
核心是“归一化滑移比 → 摩擦系数”的分段线性牵引曲线 GetTractionCoefficientFromRatio:峰值角 sfTractionPeakAngle = 1.0、极限角 sfTractionMinAngle = 2.5(均乘以损失系数);普通轮胎在峰值前线性升到 TractionCurveMax,然后线性降到 TractionCurveMin;拉力胎(HF_HAS_RALLY_TYRES)相反,滑移越大抓地越高;最后乘以偏置与损失;翘头模式下驱动后轮额外增益并封顶 4.0 src/dev_ng/game/Vehicles/wheel.cpp:94-97、src/dev_ng/game/Vehicles/wheel.cpp:3162-3212。
IntegrateCalculateForces 把载荷、材质、损坏转换成力 src/dev_ng/game/Vehicles/wheel.cpp:4165-4690:
| 阶段 | 规则 | 证据 |
|---|---|---|
| 载荷系数 | load / (静态力 × g × 质量);全油门起步时按低速牵引损失降低(越野与上坡时减弱该效应) | src/dev_ng/game/Vehicles/wheel.cpp:4169-4203 |
| 载荷敏感 | 每 +10% 载荷 −1% 摩擦(上限 5);可选极端载荷衰减(默认关) | src/dev_ng/game/Vehicles/wheel.cpp:4205-4216、src/dev_ng/game/Vehicles/wheel.cpp:4097-4098 |
| 速度刚度 | 刚度随速度上升(0.1/ m·s⁻¹,上限 5) | src/dev_ng/game/Vehicles/wheel.cpp:4230-4233、src/dev_ng/game/Vehicles/wheel.cpp:4125-4126 |
| 牵引损失 | 材质抓地 × TractionLossMult(竞技场模式 ×0.25)、湿滑、轮胎磨损;轮辋(健康 ≤0)前 0.55/后 0.38 并带随机;漂移胎前 0.75/后 0.58;瘪胎按健康插值 | src/dev_ng/game/Vehicles/wheel.cpp:4247-4309、src/dev_ng/game/Vehicles/wheel.cpp:4113-4119 |
| 偏置修正 | 轮损坏、烧胎 ×0.3、降抓地、抓地倍率、作弊 ×1.15/×1.30 | src/dev_ng/game/Vehicles/wheel.cpp:4315-4331、src/dev_ng/game/Vehicles/wheel.cpp:4109-4111 |
| 横向 | 侧偏角 atan2(-v_side, max(1,|v_fwd|)) 归一化到 TractionCurveLateral;低速时叠加“横向弹簧”(网络克隆禁用以免偏离);外倾修正 | src/dev_ng/game/Vehicles/wheel.cpp:4341-4418 |
| 纵向 | 驱动力在最小抓地范围内按比例给出滑移比;超出时按滑移增长率逐步增加(TC 作弊限幅),并对减小方向平滑;刹车类似(ABS 限幅 1.5) | src/dev_ng/game/Vehicles/wheel.cpp:4449-4515、src/dev_ng/game/Vehicles/wheel.cpp:4134-4146 |
| 合成 | 横向/纵向比组成向量,模长查牵引曲线得总系数,按 载荷 × 系数 / 模长 缩放;刹车打滑时力方向改为与速度相反 | src/dev_ng/game/Vehicles/wheel.cpp:4618-4661 |
这是一种“摩擦椭圆(圆)+ 分段线性曲线”的简化模型,而非 Pacejka 公式(推断:源码中未见 Pacejka 系数,曲线完全由三个 handling 参数和两个常数角定义)。
4.6 下压力、磨损与爆胎#
UpdateDownforce:按“前向速度 / 最大平地速度”的平方在最小与满下压力间插值;CF_USE_DOWNFORCE_BIAS车型前后分别取扰流件(VEH_EXTRA_6/VEH_EXTRA_1)是否完好;有扰流改装时使用更高倍率;满下压力会抬高悬挂 0.08 并标记更新src/dev_ng/game/Vehicles/wheel.cpp:7529-7672。空气阻力侧同样按扰流件损坏削弱下压力并相应增加阻力src/dev_ng/game/Vehicles/Automobile.cpp:1717-1749。- 轮胎温度/磨损
ProcessTyreTemp、UpdateTyreWear;损坏ApplyTyreDamage、ProcessWheelDamage、ProcessWheelBurst、DoBurstWheelToRimsrc/dev_ng/game/Vehicles/wheel.cpp:5443-5510、src/dev_ng/game/Vehicles/wheel.cpp:6675-6926、src/dev_ng/game/Vehicles/wheel.cpp:6978-7033。
5. 变速箱与引擎:CTransmission#
| 方面 | 实现 | 证据 |
|---|---|---|
| 状态 | 档位/上一档、标志(换档计时、持续油门、按速度选档、倒档选择、音频建议升档、负载)、档位比数组 [MAX_NUM_GEARS+1]、驱动力、转速比、离合比、进气压力、引擎健康、氮气/KERS 剩余 | src/dev_ng/game/Vehicles/Transmission.h:52-61、src/dev_ng/game/Vehicles/Transmission.h:184-229 |
| 档位比 | 倒档 1/-0.3、一档 1/0.3(低速扭矩与近比变速箱再缩放)、顶档 0.9;中间档用“递进系数 1.1”公式(几何级数版本保留但关闭) | src/dev_ng/game/Vehicles/Transmission.cpp:2114-2169、src/dev_ng/game/Vehicles/Transmission.cpp:47-50、src/dev_ng/game/Vehicles/Transmission.cpp:2113 |
Process | 用驱动轮平均地速与“车身相对轮下地面”的前向速度,ProcessGears 换档,然后 ProcessEngine 或 CVT 版本求驱动力;失火时输出反向力;飞机乘以气动损伤推力倍率 | src/dev_ng/game/Vehicles/Transmission.cpp:240-317 |
| 调用点 | CAutomobile::ProcessPhysics 统计驱动轮(烧胎时忽略锁死的非驱动轮),低档位时根据路面噪声或拖车臂负载设置“负载”标志;直升机驱动力清零;断轮按比例削减 | src/dev_ng/game/Vehicles/Automobile.cpp:3367-3452 |
| 引擎健康 | 最大 1000;400 散热器爆裂、200 漏油、<0 起火、−4000 完全报废;漏油速率与低油阈值 | src/dev_ng/game/Vehicles/Transmission.h:26-41 |
| 船/潜艇 | ProcessBoat / ProcessSubmarine | src/dev_ng/game/Vehicles/Transmission.h:69-70 |
6. 空气动力、飞行器、水上与轨道#
6.1 空气阻力(线性阻尼)#
CAutomobile::UpdateAirResistance 不施加显式阻力,而是设置 frag archetype 的 LINEAR_C/LINEAR_V/LINEAR_V2 阻尼;非玩家车只在“物理 LOD + 慢速区”状态改变时才重算(m_AirResistanceState 缓存);慢速区乘 1.1(否则 0.9);玩家可受强制阻力倍率与尾流(slipstream)影响;dummy 实例共享 archetype,注释承认这“有点可疑”但实践无问题 src/dev_ng/game/Vehicles/Automobile.cpp:1648-1781。
6.2 飞行器#
CAutomobile::ProcessPhysics 统一调用虚函数 ProcessFlightHandling src/dev_ng/game/Vehicles/Automobile.cpp:3625:
CRotaryWingAircraft::ProcessFlightHandling:全油门模式、空中判定、按飞行设置阻尼;旋翼转速与健康 >0 时处理输入,并在旋翼接触水面时把直升机往水下拉(m_fSubmergeLevelToPullHeliUnderwater)src/dev_ng/game/Vehicles/Heli.cpp:2051-2100;CHeli::ProcessFlightModel、UpdateRotorSpeed、ProcessPhysics分别见src/dev_ng/game/Vehicles/Heli.cpp:3222、src/dev_ng/game/Vehicles/Heli.cpp:4813、src/dev_ng/game/Vehicles/Heli.cpp:5627。CPlane::ProcessFlightHandling:溺水熄火;左右机翼都断裂或报废时不再计算飞行模型;可垂直起降的飞机按m_fCurrentVerticalFlightRatio混合ProcessVerticalFlightModel与ProcessFlightModelsrc/dev_ng/game/Vehicles/Planes.cpp:2555-2597、src/dev_ng/game/Vehicles/Planes.cpp:5723。- 飞机在特技模式或带
m_fExtraLiftWithRoll时,轮子积分器的重力会按横滚角缩减src/dev_ng/game/Vehicles/wheel.cpp:7706-7719。
6.3 水上与两栖#
CBoat::ProcessPhysics:先更新浮力 LOD(锚泊低 LOD 模式下直接返回),调用基类、gadget 物理;残骸下沉逐步减小浮力;巡逻艇/dinghy5 这类 articulated 船只在最后一个时间片施加浮力并按时间片数放大步长(克隆单时间片时 ×2 的变通)src/dev_ng/game/Vehicles/boat.cpp:1578-1676。CBoatHandling作为组件被CBoat与CAmphibiousAutomobile复用src/dev_ng/game/Vehicles/Boat.h:63-80、src/dev_ng/game/Vehicles/AmphibiousAutomobile.h:89。CSubmarine全部委托CSubmarineHandling(含ProcessBuoyancy)src/dev_ng/game/Vehicles/Submarine.h:180-192。- 河流浮力探测在
DoProcessControl_OnDeferredTaskCompletion中异步提交(非 dummy、未附着或挂在 Cargobob 上)src/dev_ng/game/Vehicles/Vehicle.cpp:25211-25223。浮力本身见 09-physics。
6.4 火车#
轨道上的 CTrain 先 ProcessTrainControl、UpdatePosition(沿轨道节点推进位置,决定 LOD 状态),仅在 ShouldDoFullUpdate() 时才调用 CVehicle::ProcessPhysics;脚本创建或不在轨道上的车厢走普通物理并同步“上一矩阵” src/dev_ng/game/Vehicles/train.cpp:5371-5420。
7. 损坏:CVehicleDamage 与 CVehicleDeformation#
7.1 健康分量#
CVehicleDamage 维护车身健康、油箱健康与油量、机油、引擎健康(存于 CTransmission)、轮胎/悬挂健康,以及最多 3 个弹跳面板 src/dev_ng/game/Vehicles/vehicleDamage.h:668-760。常量:标准健康 1000、油量 65、机油 5、油箱 700 开始泄漏、0 起火、−1000 报废、泄漏速率 2.5 src/dev_ng/game/Vehicles/vehicleDamage.h:650-662。
ApplyDamage 中:碰撞伤害按 sfVehDamImpactMult × m_fCollisionDamageMult × (handling 质量 / 实际质量) 缩放;武器伤害按 m_fWeaponDamageMult × 脚本缩放(坦克作为伤害来源时不再缩放)src/dev_ng/game/Vehicles/vehicleDamage.cpp:5192、src/dev_ng/game/Vehicles/vehicleDamage.cpp:5457、src/dev_ng/game/Vehicles/vehicleDamage.cpp:5752-5801。
CVehicleDamage::Process(由各车型 DoProcessControl 调用)读取本帧最显著的碰撞记录,先交给 CVehicleIntelligence::ProcessCollision,MP 中驾驶员无敌时清掉形变冲击,竞技场模式另有卡死检测,网络克隆只按碰撞冲量和应用伤害(权威在拥有者端)src/dev_ng/game/Vehicles/vehicleDamage.cpp:4349-4410、src/dev_ng/game/Vehicles/Automobile.cpp:2054-2076。可调参数 CVehicleDamage::Tunables(CTuning)包括同向判定角、过错速度阈值、C&C 耐久伤害冲量区间与通缉冲量阈值 src/dev_ng/game/Vehicles/VehicleDamage.psc:4-13、src/dev_ng/game/Vehicles/vehicleDamage.h:671-691。
7.2 形变纹理#
形变用一张“局部偏移 → 3D 位移”的损坏贴图表示:逻辑 128×128,物理宽 128,高度 PS3 为 96、其余 128;每像素 4 字节 src/dev_ng/game/shader_source/Vehicles/vehicle_common_values.h:16-23、src/dev_ng/game/shader_source/Vehicles/vehicle_common_values.h:39、src/dev_ng/game/shader_source/Vehicles/vehicle_common_values.h:68。纹理是有限资源,用缓存 ms_TextureCache 分配给最近受损的车辆:
| 平台 | GPU_DAMAGE_WRITE_ENABLED | 同时受损车辆 | 每车每帧冲击 | 实现差异 | 证据 |
|---|---|---|---|---|---|
| PS4 / Xbox One / PC | 1 | 40 | 16 | 冲击写入由 GPU 完成;PC 使用滚动纹理数组(2 × MAX_GPUS)+ 互斥锁做 CPU 读回 | src/dev_ng/game/shader_source/Vehicles/vehicle_common_values.h:47-59、src/dev_ng/game/renderer/ApplyDamage.h:19、src/dev_ng/game/Vehicles/vehicleDamage.h:51-56、src/dev_ng/game/Vehicles/vehicleDamage.cpp:4076-4110 |
| Xbox 360 / PS3 | 0 | 16 | 4 | CPU 在锁定纹理中直接写像素(打包为 float);常量注释要求与 RAGE 的 EDGE 程序 grcore/edge_vehicledamage.spa 保持一致(推断:PS3 在 SPU/EDGE 上做顶点形变,本页未深入该 RAGE 文件) | src/dev_ng/game/shader_source/Vehicles/vehicle_common_values.h:13-14、src/dev_ng/game/shader_source/Vehicles/vehicle_common_values.h:61-65、src/dev_ng/game/Vehicles/vehicleDamage.h:83-86、src/dev_ng/game/Vehicles/vehicleDamage.h:226-237 |
纹理像素读取在 GPU 写入平台上是 R8G8B8A8_SNORM(/128 得 −1..1),在旧平台上是一个 float 打包三个 8 位分量 src/dev_ng/game/Vehicles/vehicleDamage.h:212-240。纹理缓存在 CVehicleDeformation::TexCacheInit 中按配置大小构建(旧平台 MP 下减半)src/dev_ng/game/Vehicles/vehicleDamage.cpp:4036-4061,并由 CGame 的 init/shutdown 与每帧 TexCacheUpdate 管理 src/dev_ng/game/core/game.cpp:1805、src/dev_ng/game/core/game.cpp:3039。
7.3 形变流程#
证据:ApplyCollisionImpact 的前置条件(MP 无敌、禁用形变、残骸)与“玩家撞击加倍/脚本减伤”src/dev_ng/game/Vehicles/vehicleDamage.cpp:2218-2255;冲击存储 src/dev_ng/game/Vehicles/vehicleDamage.h:291-295、src/dev_ng/game/Vehicles/vehicleDamage.cpp:2692;ApplyDeformations 分配纹理、两条平台路径与清空存储 src/dev_ng/game/Vehicles/vehicleDamage.cpp:2841-2960;CApplyDamage::EnqueueDamage src/dev_ng/game/renderer/ApplyDamage.h:63-94;GPU 写完后渲染侧调用 CVehicle::SetDamageUpdatedByGPU(true, ...),后者在互斥锁保护下把车辆加入 CPhysics::ms_pDamagedVehicles src/dev_ng/game/renderer/ApplyDamage.cpp:888、src/dev_ng/game/Vehicles/Vehicle.cpp:2489-2511、src/dev_ng/game/physics/physics.cpp:1319-1330;PreSimUpdate 的第一个时间片调用 ProcessDamagedVehicles,每帧最多处理 MAX_BOUND_DEFORMATION_PER_FRAME = 2 辆(有待定边界更新的车除外)src/dev_ng/game/physics/physics.cpp:1374-1381、src/dev_ng/game/physics/physics.cpp:1332-1358、src/dev_ng/game/shader_source/Vehicles/vehicle_common_values.h:54-58。HandleDamageAdded 根据纹理更新碰撞边界(ApplyDamageToBound)、轮子悬挂(ProcessPhysics2 中按纹理更新带 WCF_UPDATE_SUSPENSION 的轮子)、骨骼与玻璃 src/dev_ng/game/Vehicles/vehicleDamage.cpp:3086、src/dev_ng/game/Vehicles/vehicleDamage.cpp:3309、src/dev_ng/game/Vehicles/Automobile.cpp:4792-4817。
7.4 爆炸#
CAutomobile::BlowUpCar:网络克隆或迁移中的车只发送 CBlowUpVehicleEvent 由拥有者执行;本地执行时记录破坏值、可选添加爆炸、先把健康设为 0(“必须在 AddExplosion 之前,否则会炸两次”)、BlowUpCarParts 让部件飞散、杀死车内乘员、连带引爆所挂拖车,最后生成残骸火焰特效 src/dev_ng/game/Vehicles/Automobile.cpp:6405-6625。爆炸参数(部件速度、LOD 半径)来自 vehiclelayouts 的 CVehicleExplosionInfo,加载时校验 LOD 半径单调递增 src/dev_ng/game/Vehicles/Metadata/VehicleMetadataManager.cpp:1060-1075。
8. LOD 与虚拟化:real / dummy / superdummy / 时间片#
8.1 四种模式#
| 模式 | LOD 标志 | 物理实例 | 碰撞 / 重力 / dummy 约束 | 轮子接触 | 变速箱与轮子积分 | 证据 |
|---|---|---|---|---|---|---|
| real | 无 | frag 实例 | 全部 | 物理碰撞结果 | 是 | src/dev_ng/game/vehicleAi/VehicleAILod.cpp:28-43 |
| dummy | AL_LodDummy | dummy 实例(有拖车时保留 frag) | 有 / 有 / 有 | 虚拟路面 | 是 | src/dev_ng/game/vehicleAi/VehicleAILod.h:35-44、src/dev_ng/game/Vehicles/Automobile.cpp:5123-5141 |
| superdummy | AL_LodSuperDummy | dummy 实例 | 无 / 无 / 无 | 路径节点 | 否(ProcessPhysics 直接返回) | src/dev_ng/game/vehicleAi/VehicleAILod.h:46-55、src/dev_ng/game/Vehicles/Automobile.cpp:3220-3227 |
| 时间片 | AL_LodTimeslicing(叠加在上述之上) | — | — | — | AI/控制只在被选中的帧做全量更新,其余帧插值 | src/dev_ng/game/vehicleAi/VehicleAILod.h:57-66、src/dev_ng/game/vehicleAi/VehicleAILodManager.cpp:202-228 |
eVehicleDummyMode 为 VDM_NONE/REAL/DUMMY/SUPERDUMMY src/dev_ng/game/Vehicles/VehicleDefines.h:92-98;CVehicleAILod 有当前、阻止(每帧重置)与强制三组标志,强制标志总会被并入,__BANK 下还有调试高/低覆盖 src/dev_ng/game/vehicleAi/VehicleAILod.h:100-124。任务车默认阻止事件扫描/dummy/superdummy(AL_DefaultMissionBlockedLodFlags)src/dev_ng/game/vehicleAi/VehicleAILod.h:68-70。
8.2 CVehicleAILodManager::Update#
| 参数 | 默认值 | 证据 |
|---|---|---|
屏外缩放豁免半径(ms_fRealDistance)/ dummy 距离 / superdummy 距离 / 停放 superdummy 距离 | 15 / 40 / 75 / 40 m | src/dev_ng/game/vehicleAi/VehicleAILodManager.cpp:41-44 |
| 屏外距离缩放、滞回、远离人口中心距离 | ×3 / 5 m / 135 m | src/dev_ng/game/vehicleAi/VehicleAILodManager.cpp:45-48 |
| 转 dummy / 转 real 最小间隔 | 2000 / 500 ms | src/dev_ng/game/vehicleAi/VehicleAILodManager.cpp:50-51 |
| N-LOD 上限:real / dummy / 非时间片 / 真实驾乘 ped | 10 / 20 / 14 / 24(注释:旧主机为 12) | src/dev_ng/game/vehicleAi/VehicleAILodManager.cpp:52-56 |
| 时间片:每帧最大更新数(配置)、最小周期 4 帧、允许屏内时间片的距离 75/150 m | — | src/dev_ng/game/vehicleAi/VehicleAILodManager.cpp:87-91 |
| dummy / superdummy 约束模式 | 距离+旋转 / 仅距离 | src/dev_ng/game/vehicleAi/VehicleAILodManager.cpp:117-122 |
算法 src/dev_ng/game/vehicleAi/VehicleAILodManager.cpp:388-862:
- 优先级距离以人口控制点的
m_conversionCentre为中心(本地玩家/脚本相机位置另用于假乘员转换)src/dev_ng/game/vehicleAi/VehicleAILodManager.cpp:406-414、src/dev_ng/game/vehicleAi/VehicleAILodManager.cpp:866;若该中心移动超过 10 m(距离平方 100)或倒计时到 0,则重新FindVehiclesByPriority:对每辆车计算有效距离平方——屏外且超出 15 m 时乘以3² = 9,再按距离排序src/dev_ng/game/vehicleAi/VehicleAILodManager.cpp:436-459、src/dev_ng/game/vehicleAi/VehicleAILodManager.cpp:161-163、src/dev_ng/game/vehicleAi/VehicleAILodManager.cpp:954-958、src/dev_ng/game/vehicleAi/VehicleAILodManager.cpp:978。 - 优先级数组被分成
ms_iVehiclePriorityCountdownMax = 3批,每帧只处理一批(由近到远)src/dev_ng/game/vehicleAi/VehicleAILodManager.cpp:461-467。 - 拖车、挂在拖车上的车、被拖的车不自行转换(跟随牵引车)
src/dev_ng/game/vehicleAi/VehicleAILodManager.cpp:492-506。 - 按当前模式与带滞回的距离阈值求期望模式,期间调用
GetCanMakeIntoDummy校验;N-LOD 名额用尽时把期望降一级;再交给车辆ProcessOverriddenDummyMode覆盖src/dev_ng/game/vehicleAi/VehicleAILodManager.cpp:512-610。 - 满足最小间隔时调用
TryToMakeFromDummy(停放车、自行车、飞机、船、无约束的车跳过清空检测)或TryToMakeIntoDummysrc/dev_ng/game/vehicleAi/VehicleAILodManager.cpp:615-675。 - 时间片判定:任务要求时间片,或“静止的 superdummy / 直升机(无 superdummy 支持,real 也可时间片)”且通过可见性检测(或非时间片名额已满)
src/dev_ng/game/vehicleAi/VehicleAILodManager.cpp:677-733。 - 每帧最多把 1 辆车的“假乘员”转成真 ped;一轮扫描结束后若真驾乘 ped 超额,则从最远处把一辆车转回假乘员
src/dev_ng/game/vehicleAi/VehicleAILodManager.cpp:472-474、src/dev_ng/game/vehicleAi/VehicleAILodManager.cpp:792-842。
ShouldDoFullUpdate:不在时间片模式则总是全量;被强制则全量;允许跳过时跳过;否则看本帧是否被选中 src/dev_ng/game/vehicleAi/VehicleAILodManager.cpp:202-228。新生成的车在 MakeVehicleIntoDummyBasedOnDistance 中按 CalcDesiredLodForPoint(只用 dummy/superdummy 距离)直接转换 src/dev_ng/game/vehicleAi/VehicleAILodManager.cpp:308-332。
8.3 转换的实现#
TryToMakeIntoDummy:节流计时、GetCanMakeIntoDummy、从 real 转换时做 dummy 实例清空测试、superdummy 要求轮胎完好、拖车与货物车须能一起转换;设置 LOD 标志后调用SwitchToDummyPhysics或SwitchToSuperDummyPhysicssrc/dev_ng/game/Vehicles/Vehicle.cpp:6981-7200。SwitchToSuperDummyPhysics:给所有轮子置WF_DUMMY;frag 实例清空类型/包含标志,dummy 实例设为GTA_BOX_VEHICLE_TYPE;清零 collider 速度(保存以便 superdummy 使用),切到 dummy 实例并停用 frag 实例src/dev_ng/game/Vehicles/Vehicle.cpp:7634-7700。SwitchToDummyPhysics:缓存首轮材质 ID 作为 dummy 路面材质;不使用 dummy 物理时仅缩小 frag 的碰撞包含集,否则从 superdummy 回到 dummy 时恢复碰撞与约束src/dev_ng/game/Vehicles/Vehicle.cpp:7832-7880。- AI 侧在每次 AI 收尾时检查:任务阻止 dummy、follow route 为空或约束剧变时强制转回 real,转不回且没有路线时直接停用物理,防止掉出世界
src/dev_ng/game/vehicleAi/VehicleIntelligence.cpp:1153-1199。
8.4 superdummy 的运动#
superdummy 不进物理模拟:插值任务(工作线程)在全量更新帧调用 ProcessSuperDummy,用节点列表或 follow route 把最多 4 个轮子(拖车用中/后轮)采样到路面上并据此设置位置/朝向;失败时用 m_BackupFollowRoute.ProcessSuperDummy 兜底(新版 AI 本身会在避障延迟任务里先处理)src/dev_ng/game/Vehicles/Vehicle.cpp:8284-8366、src/dev_ng/game/Vehicles/Vehicle.cpp:8712-8800、src/dev_ng/game/vehicleAi/task/DeferredTasks.cpp:244-252。superdummy 车之间的碰撞通过 ProcessPreComputeImpactsSuperDummyCar 处理 src/dev_ng/game/Vehicles/Vehicle.cpp:20518-20525。
8.5 时间片插值#
非全量帧中,时间片车调用 ProcessInterpolationForTimeslicedLod 朝目标位姿插值;长距离寻路与直升机寻路任务在此帧仍执行 ProcessTimeslicedUpdate 以持续请求节点 src/dev_ng/game/Vehicles/Vehicle.cpp:8286-8313、src/dev_ng/game/Vehicles/vehicle.h:1031-1072。ProcessControl 用 m_fTimeSinceLastAiUpdate + dt 作为全量更新的时间步 src/dev_ng/game/Vehicles/Vehicle.cpp:24578-24595。
9. 平台与构建差异#
| 条件 | 影响 | 证据 |
|---|---|---|
__PS3(SPU_WHEEL_INTEGRATION) | 轮子积分可在 SPU 运行(wheelspu.job) | src/dev_ng/game/Vehicles/wheel.h:51、src/dev_ng/game/Vehicles/wheelspu.job:1-37 |
GPU_DAMAGE_WRITE_ENABLED(PS4/XB1/PC) | GPU 写损坏纹理、40 车 / 16 冲击;PC 滚动纹理数组 | src/dev_ng/game/shader_source/Vehicles/vehicle_common_values.h:47-59 |
__BANK | ms_bUseWheelIntegrationTask 可被 -disablewheelintegrationtask 关闭(主线程直算);handling 重载 ReloadHandlingData | src/dev_ng/game/Vehicles/VehicleFactory.cpp:1469、src/dev_ng/game/Vehicles/wheel.cpp:7929-7935、src/dev_ng/game/Vehicles/handlingMgr.cpp:1855-1877 |
VERIFY_OLD_HANDLING_DAT / CONVERT_HANDLING_DAT_TO_META(默认 0) | 旧 handling.dat 校验/转换工具路径 | src/dev_ng/game/Vehicles/handlingMgr.h:27-28、src/dev_ng/game/Vehicles/handlingMgr.cpp:1923-1936 |
RSG_GEN9 | 非扩展改装车型的涡轮功率修正 | src/dev_ng/game/Vehicles/Transmission.cpp:167-172 |
!__FINAL / NO_VEH_DAMAGE_PARAM | 全局禁用车辆损坏/形变的调试开关 | src/dev_ng/game/Vehicles/vehicleDamage.cpp:2226-2233 |
10. 约束与边界行为#
- 重力的唯一施加点:跑轮子积分时 collider 的重力被关闭,若绕过
StartWheelIntegratorTask修改流程会导致重力缺失或重复(推断,依据 4713-4744 的开关逻辑)。 - 积分任务期间 articulated body 只读:
PHARTICULATEDBODY_MULTITHREADED_VALDIATION下主线程被标为只读,直到ProcessPhysics2取回结果;需要修改刚体的逻辑(磁铁、网络混合)被推迟到第三遍src/dev_ng/game/Vehicles/wheel.cpp:7897-7907、src/dev_ng/game/Vehicles/Automobile.cpp:4760-4765、src/dev_ng/game/Vehicles/Automobile.cpp:4891-4907。 - 轮子数上限:积分器断言
nNumWheels <= INTEGRATION_MAX_NUM_WHEELSsrc/dev_ng/game/Vehicles/wheel.cpp:7786;superdummy 最多采样 4 轮src/dev_ng/game/Vehicles/Vehicle.cpp:8743。 - 网络:克隆车禁用横向弹簧、伤害由拥有者决定、
BlowUpCar转为事件;所有权变化后残留的 dummy 约束会在物理中被清除src/dev_ng/game/Vehicles/wheel.cpp:4357-4362、src/dev_ng/game/Vehicles/vehicleDamage.cpp:4404-4410、src/dev_ng/game/Vehicles/Automobile.cpp:3207-3213。 - 残骸不再形变(除非有待更新的边界),以免碎块网格与边界不一致
src/dev_ng/game/Vehicles/vehicleDamage.cpp:2241-2243。
11. 未决问题与证据不足#
- 未找到
handling.meta数据本体,无法给出具体车型参数。 WheelIntegrationEvaluate、IntegrateTyreAccel、ProcessResultInternal与IntegrationPostProcess(约 1,500 行)只按结构描述,未逐式推导;ProcessEngine的扭矩曲线与ProcessGears的换档阈值未展开。- 自行车/摩托(
CBike::ProcessPhysics的平衡、侧倾约束)、CLandingGear、CPropeller、CAnchorHelper的细节未展开,仅列出文件。 CVehicleDeformation::ApplyCollisionImpact的冲量→位移标定常数与ApplyDamageToBound的顶点处理未逐行分析。