刚体状态应存位置pos和速度vel两个vec2、质量mass(或倒质量invmass)、角度angle及角速度angularvel;力与加速度不存储,每帧重算;积分推荐半隐式欧拉以保稳定。

刚体状态怎么存才方便积分
直接用两个 vec2(比如 sf::Vector2f 或自定义结构体)存位置 pos 和速度 vel,再加一个标量 mass 和旋转相关量(如角度 angle、角速度 angularVel)。别把力或加速度存在状态里——它们是瞬时量,每次更新都要重新算。
关键点:
-
mass不能为 0,否则除零;建议设默认值 1.0f,或用1.0f / invMass存倒质量更安全 - 位置和速度必须用同一坐标系(通常是世界坐标),别混用局部/屏幕坐标
- 如果后续要支持碰撞,
pos应代表质心,不是左上角
重力怎么加才符合物理直觉
重力是恒定外力,按牛顿第二定律转换成加速度: acc = gravity * (1.0f / mass)。但更稳妥的做法是直接累加力,最后统一除质量——这样多个力(比如推力、风力)能自然叠加。
实操建议:
- 定义全局常量
const vec2 GRAVITY = {0.0f, 980.0f};(单位用像素/秒²,匹配常见渲染坐标系 Y 向下) - 每帧开始清空临时力缓冲:
forceAccum = {0.0f, 0.0f}; - 然后叠加:
forceAccum += GRAVITY * body.mass;(注意:这里是力,不是加速度) - 积分前才算加速度:
vec2 acc = forceAccum * body.invMass;
用什么积分器?欧拉够不够用
显式欧拉(pos += vel * dt; vel += acc * dt;)实现最简单,但能量不守恒,高速或大 dt 下会明显漂移甚至爆炸。真实项目中至少该用半隐式欧拉(先更新 vel,再用新 vel 更新 pos),它保持稳定性且代码几乎不增加。
推荐写法:
vel += acc * dt; pos += vel * dt;
注意点:
- 别写成
pos += (vel + acc * dt) * dt(那是显式,错) - dt 必须是真实帧间隔(如
clock.restart().asSeconds()),别用固定 1/60 硬编码,除非你做锁帧 - 角运动同理:
angularVel += torque * invInertia * dt;,再更新angle
为什么物体落地后还在微微抖动
这是最常见的数值误差表现:当物体“接触地面”时,重力持续下拉,速度变负,下一帧又向上冲一点,形成震荡。这不是引擎坏了,而是缺少约束处理。
紧急修复(非物理精确但实用):
- 检测到
pos.y > groundY且vel.y (向下撞地),就强制设 <code>vel.y = 0并pos.y = groundY - 加个微小的“地面容忍阈值”,比如
if (pos.y > groundY - 1.0f),避免浮点抖动触发误判 - 真正解决要引入冲量约束(如 Baumgarte stabilization),但那已是碰撞响应范畴,不在纯积分范围内
手写 2D 刚体引擎最难的从来不是积分公式,而是让多个物体堆叠时不沉进彼此、不疯狂弹跳——那需要接触检测 + 冲量求解,比积分本身复杂一个数量级。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











