本节摘要:能玩的车和能玩的人很少是全刚体机构。载具常用射线或胶囊轮测地,用弹簧阻尼当悬挂,用轮胎摩擦圆给侧向力和驱动力。角色用运动学胶囊去扫世界,上台阶、爬坡、贴墙滑,布娃娃只在倒地时启用。专用近似换来可控手感,代价是不是真实多体力学。把选择写明白,比假装“物理正确”重要。
阅读完本节,你应当能够:
四轮车:车身一个刚体。每个轮从轮拱往下打射线(或胶囊扫掠),命中距离决定悬挂压缩。弹簧力 F = k * compression + d * compression_rate 沿地面法向加在车身对应锚点,产生支撑和力矩(俯仰侧倾)。轮子视觉模型跟着命中点转,不必是物理圆柱——圆柱轮在凸起上会卡住,射线更宽容。
驱动力沿车头方向,侧向力抵抗滑移:轮胎速度分解为纵向、侧向,侧向力试图把侧向速度刹掉,类似摩擦约束,但写在力层按固定步积分进车身。合力投影到摩擦圆:sqrt(Fx^2+Fy^2) <= mu * N,N 即法向载荷。急刹时纵向用满,侧向变小,这就是刹车容易甩尾的游戏版。
for each wheel: hit = raycast(anchor, down, length) if not hit: 离地, 力=0 else: N = springDamper(compression) applyForceAt(anchor, N * normal) Fx, Fy = tireModel(slip, N) clamp to friction circle applyForceAt(contact, Fx*long + Fy*lat)
| 方案 | 手感 | 卡地形 | 实现 |
|---|---|---|---|
| 四圆柱真接触 | 真实但难调 | 易卡边 | 重 |
| 射线轮 | 街机到拟真可调 | 少 | 中 |
| 纯运动学沿路 | 轨道车 | 无 | 轻 |
| 完整多体悬挂 | 拟真模拟器 | 中 | 很重 |
街机用射线加强阻尼;模拟器才上多体。中间路线:射线悬挂加更细的轮胎曲线。我做可玩原型一定先射线,卡地形会毁整局。

差速、防侧倾杆、手刹都可以在力层加。不要先做完真齿轮。手感旋钮:悬挂 k、d,轮胎 mu,质心高度。质心高易翻车,这是真物理,射线轮也保留。
角色控制器(KCC)每帧给出期望位移(来自输入和动画),用胶囊做扫掠:先水平,碰到墙则沿墙切向滑,再竖直贴地。地面探测用脚下额外射线,决定是否 grounded。上台阶:若阻挡很矮,抬高胶囊再试水平。爬坡:地面法向与上方向夹角超过阈值则视为墙,滑下去。这样角色不会变成刚体盒子在台阶上磕绊。
KCC 不是动态刚体,别的物体怎么跟它碰?常见:角色对世界运动学,对可推箱子用一个动态胶囊代理施力,或短时切换动态。全动态人形走路极难控:一步就会被地面接触扭倒。布娃娃用于倒地、死亡、过场,走路用 KCC。切换时把布娃娃姿态对齐胶囊,速度清零或继承,下一帧再启用碰撞,避免姿势重叠爆炸。
💡 关键直觉:可玩性物理的目标函数是手感,不是能量守恒。射线轮和 KCC 是玩法模块,请用玩法测试验收,不要用金字塔休眠那套刚体测试验收。
坡度、台阶高度、皮肤半径是关卡设计参数。改网格而不改这些数,角色会在美术“好看的坎”上卡住。把参数暴露给关卡,不要写死在求解器里。
车身是动态刚体,吃 PGS 接触,所以车可以压箱子。轮射线不要再对车身自己检测。角色胶囊对动态物体:推箱子用速度或施加力,力要有上限,免得箱子被弹飞。箱子推角色:要么角色让位(扫掠时把动态体当墙),要么角色被推动(这帧改成动态)。同时做会振荡。
⚠️ 常见坑:角色脚下射线打到自己的布娃娃手臂,瞬间判定离地,动画跳。射线过滤掉自己和附件层。
载具空中:四轮离地时悬挂力为 0,车身只受重力和空气,翻滚由刚体积分负责。不要在空中还加“自动回正”除非设计需要。回正是控制,写在控制器,别写进轮胎。
测试:平地加速不侧滑(mu 够);急转摩擦圆起作用能漂;20 厘米台阶角色能上,80 厘米不能;45 度坡能走,70 度当墙。把这些写成关卡测试盒,调参才有锚。
网络同步:KCC 和射线轮都要在固定步里跑,输入驱动。视觉轮转动可以渲染插值。7.2 节会要求控制器步进可复现,本节不要读可变帧 dt。
摩托车、飞行载具不在最小集。先四轮加胶囊。飞行是另一套升力模型。不要把 5.4 写成载具百科。动手优先:一辆能压箱子的射线车,一个能上台阶的胶囊,比十种载具公式有用。
质心、轮距、轴距决定俯仰。刹车点头是悬挂弹簧的真现象,可用来验收弹簧是不是加在锚点而不是质心——加在质心只有平移没有点头。
车:质心高度、轮距、悬挂 k 和 d、轮胎 mu、驱动扭矩。一次改一个,在测试环道上跑:直线加速不跑偏(轮射线左右对称)、刹车点头(力加在锚点)、急转摩擦圆(速度高时侧滑)。跑偏先查左右悬挂锚点镜像,再查轮胎力坐标系。
角色:胶囊半径、高度、台阶高、坡度角、皮肤、最大推箱力。测试盒放 10/20/40/80 厘米台阶和 30/45/60/70 度坡。策划改关卡网格时跑一遍测试盒。卡住不要先改 KCC 核心,先问台阶是不是超过参数。
布娃娃切换:倒地时把每段刚体对齐骨骼,速度继承胶囊速度,延迟一帧开碰撞。立刻开碰撞会因姿势重叠炸飞。起来时反向:关布娃娃碰撞,胶囊放到骨盆,KCC 接管。两套碰撞层永远不要同时对世界生效。
载具对角色:车是动态刚体,角色是运动学。车撞人用接触事件改角色速度或切布娃娃,不要指望 PGS 自动处理 KCC。KCC 不在求解器里。写一个“载具对角色”的专用响应,这是玩法代码。
过滤自身和附件层。脚下打到布娃娃手臂会误判离地,动画跳。层掩码是 KCC 的一部分。
会振荡:一帧你推它,一帧它把你当墙。选一种:角色让位或角色被推,力有上限。
控制器,不是轮胎。离地时悬挂力为 0,翻滚交给刚体。回正是设计需求,别伪装成轮胎力。
姿势重叠,求解器巨大穿透。延迟一帧、对齐骨骼、关一套开一套。永远不要同时对世界。
KCC 不在求解器里。写专用响应:改角色速度或切布娃娃。别指望刚体接触自动处理运动学胶囊。
刹车无点头。应加在轮锚点。
直线跑偏。先查镜像再查轮胎坐标系。
先问关卡。测试盒 10/20/40/80 厘米。
误判离地。过滤附件层。
写进控制器并承认是设计。
KCC 不在求解器。专用响应。
重叠爆炸。关一套开一套。
联机分叉。走固定步。
文档里的公式符号必须和代码注释同一张表。尤其是法向从谁指向谁、相对速度谁减谁、lambda 是力还是冲量。「04-载具与角色控制器」相关代码若混用两套符号,吸引接触和飞天会轮流出现,现场非常像随机 bug。 本条对应「04-载具与角色控制器」第 1 号备忘,和相邻条目不要合并成一句空话,分开验收。
性能上先问能不能少做。「04-载具与角色控制器」再快,也快不过把睡着的岛整岛跳过、把碎片到期删掉、把静态体移出动态表。减工作量优于把同样工作向量化。向量化平方算法只是错得更稳更快。 本条对应「04-载具与角色控制器」第 2 号备忘,和相邻条目不要合并成一句空话,分开验收。
可视化是「04-载具与角色控制器」的一部分而不是插件。接触生成时就把点、法向、深度留下来给绘制。事后从形状重新推断,会和求解器看到的数据不一致,你会修一个并不存在的偏差。 本条对应「04-载具与角色控制器」第 3 号备忘,和相邻条目不要合并成一句空话,分开验收。
固定时间步是「04-载具与角色控制器」所有数值实验的尺子。尺子在抖,你无法比较积分器,无法调 beta,无法谈确定性。谁把渲染帧时间直接喂进物理,谁就在用弹性的尺子量钢梁。 本条对应「04-载具与角色控制器」第 4 号备忘,和相邻条目不要合并成一句空话,分开验收。
「04-载具与角色控制器」里出现 NaN 要在源头断言:未归一化法向、零长度边当轴、除以过小的有效质量、四元数没归一。把 NaN 传到求解器再查,整场速度都会脏,回溯成本高一个数量级。 本条对应「04-载具与角色控制器」第 5 号备忘,和相邻条目不要合并成一句空话,分开验收。
和美术、策划交接「04-载具与角色控制器」参数时,用测试盒而不是形容词。说清楚二十厘米台阶能上、八十厘米不能,比说手感更跟手有用。测试盒还能在引擎升级后当合同跑一遍。 本条对应「04-载具与角色控制器」第 6 号备忘,和相邻条目不要合并成一句空话,分开验收。
「04-载具与角色控制器」若跨模块耦合,先单向再双向。布料先撞静地,流体先撞静箱,关节先吊静锚。双向一步到位时,你分不清是 A 推 B 写错还是 B 还力写错。控制变量不是学术,是省生命。 本条对应「04-载具与角色控制器」第 7 号备忘,和相邻条目不要合并成一句空话,分开验收。
下一章回到性能:SIMD、岛线程、空间结构,让第 3、4 章的循环在物体变多时还能在预算里。