纯c++不适合直接做物理碰撞模拟,因其缺乏内置物理引擎,需自行实现数学逻辑或集成第三方库;常见错误包括忽略运动连续性、分离轴检测、冲量累积等底层机制,仅靠aabb校正易导致穿墙、卡死、反弹异常等问题。

纯 C++ 不适合直接做物理碰撞模拟——它没内置物理引擎,得靠你自己实现数学逻辑或集成第三方库。
为什么不能只靠 std::vector 和 if 判断就搞定碰撞
常见错误是写个“两个矩形中心距离小于半宽之和”就以为完事了,结果角色穿墙、卡进地板、反弹方向错乱。这不是代码没跑起来,而是漏掉了:运动连续性(帧间穿越)、分离轴(SAT)、冲量累积、接触点求解这些底层机制。
真实游戏里,哪怕只是 AABB 碰撞,也要考虑:
- 物体在上一帧在 A 位置、下一帧在 B 位置,中间可能穿过障碍物——得做
sweep test或continuous collision detection if (x1 这类静态检测在高速移动时完全失效- 碰撞后要修改速度、位置、角速度,还可能触发回调(比如播放音效),这些逻辑散在游戏循环里极易失控
用 Box2D 是最现实的起点(不是“推荐”,是“别自己重造轮子”的实操选择)
Box2D 是 C++ 写的、开源、轻量、有完整文档,且被 Cocos2d-x、Love2D(通过绑定)等大量项目验证过。它不依赖 OpenGL 或 SDL,只吃标准 C++11 和 malloc。
立即学习“C++免费学习笔记(深入)”;
关键实操点:
- 初始化时必须调用
b2World构造函数传入重力向量,哪怕设为b2Vec2(0, 0),否则刚体不会响应力 - 所有刚体(
b2Body)必须通过b2World::CreateBody()创建,不能new b2Body——它的内存由世界管理 - AABB 碰撞器用
b2PolygonShape,圆形用b2CircleShape;形状必须通过b2Fixture关联到刚体,不能直接 attach - 每帧必须调用
b2World::Step(dt, velocityIter, positionIter),其中dt要稳定(建议固定步长如1.0f / 60.0f),否则物理会飘
示例片段(创建一个静止地板):
b2BodyDef groundDef; groundDef.position.Set(0.0f, -10.0f); b2Body* ground = world->CreateBody(&groundDef); <p>b2PolygonShape groundShape; groundShape.SetAsBox(50.0f, 10.0f); // 宽高</p><p>b2FixtureDef fixtureDef; fixtureDef.shape = &groundShape; ground->CreateFixture(&fixtureDef);</p>
如果真要手写简单碰撞,只做 AABB + 位置校正,注意三个硬约束
不是不能写,但必须接受它只能用于原型、教学或极低速 UI 元素。核心陷阱在“校正逻辑”:
- 不能只修正 X 或 Y 单轴——得按穿透深度最小的方向推离,否则斜向撞墙会卡死。要用
std::min({dx, dy, dw, dh})类似的比较 - 修正后必须设
velocity.x = 0或翻转,否则下一帧又撞回来;但翻转前得判断法线方向,不然会往墙里弹 - 多个物体同时碰撞时,顺序影响结果——先处理 A-B,再处理 B-C,可能让 B 被挤出世界边界。没有迭代求解,就别碰多体
一个典型错误校正写法:
// ❌ 错误:没考虑哪个方向穿透少
if (a.x < b.x + b.w && a.x + a.w > b.x) {
a.x = b.x + b.w; // 直接贴边,不管 y 方向是否也重叠
}
真正难的不是算“有没有撞”,而是撞完怎么让物体看起来“合理地停住、弹开、堆叠”。这背后是数值稳定性、迭代器次数、睡眠唤醒机制——这些 Box2D 已经调了十几年。自己写,三天能跑通矩形,三个月未必能稳住十个箱子堆塔。











