Box2D适合2D游戏,API简洁、性能优但无Z轴和扩展性;Bullet适合3D及仿真系统,模块化强、兼容ROS但复杂度高;选择依据是坐标维度、动态物体规模与跨语言需求。

Box2D 和 Bullet 不是“哪个更好”,而是“哪个更对”。选错一个,编译能过、运行能跑,但后期会卡在碰撞精度、内存增长、多线程扩展或调试无从下手。
Box2D 适合你写 2D 游戏时直接上手
它的 API 是为 2D 刚体设计的:没有 Z 轴概念,
b2Vec2替代btVector3,所有形状(b2CircleShape、b2PolygonShape)默认扁平、无厚度初始化极简:
b2World构造只要重力向量,step()只需传时间步长和迭代次数,没宽阶段、没 dispatcher、没 solver 配置-
常见错误现象:
立即学习“C++免费学习笔记(深入)”;
- 把
b2BodyDef::type设成b2_dynamicBody却忘了调SetAwake(true)→ 物体静止不动 - 在
step()外修改 body 位置(比如直接改SetTransform)→ 下一帧被物理系统覆盖,表现“瞬移”或抖动 - 使用
b2ChainShape拼地形时顶点数超 128 → 崩溃或断言失败(默认限制,可改但不推荐)
- 把
性能友好:单线程,典型开销
0.1–1ms/ 帧,iOS/Android 上也稳不支持软体、关节链过长易发散、不能加自定义力场——这些不是缺陷,是设计取舍
Bullet 适合你做 3D、需要扩展或对接仿真系统
它的初始化流程明确暴露物理子系统职责:
btCollisionConfiguration、btCollisionDispatcher、btBroadphaseInterface、btConstraintSolver—— 每个都能换实现-
常见错误现象:
立即学习“C++免费学习笔记(深入)”;
- 忘记调
world->addRigidBody()→ 刚体创建了但不参与模拟,像幽灵 - 用
btBoxShape时传入半尺寸(half-extents)却误传全尺寸 → 碰撞盒大出一倍 - 在多线程环境里共享
btDiscreteDynamicsWorld实例 → 内存踩踏、随机崩溃(它非线程安全,得每个线程独立 world 或加锁) -
stepSimulation(1.0f/60.0f)传固定步长但没做插值 → 运动卡顿,尤其低帧率设备
- 忘记调
支持刚体+软体+车辆约束+射线查询+自定义碰撞算法,但代价是头文件依赖深、编译慢、调试信息冗长
若项目未来要接入 ROS、Gazebo 或导出 URDF,
Bullet的数据结构和坐标约定更兼容
你真正在意的其实是这三个判断点
- 你的游戏坐标是二维平面(X/Y)还是三维空间(X/Y/Z)?→ 选
Box2D还是Bullet的第一道分水岭 - 你是否需要在运行时动态增删大量刚体(比如弹幕、碎片、粒子级物体)?→
Box2D的内存池管理更轻量,Bullet的btAlignedObjectArray易碎片化 - 你有没有可能把物理逻辑抽出来,给 Python 脚本调用或喂给训练框架?→
Bullet的 C 接口封装成熟(bullet3),Box2D几乎没有官方 C 绑定
Box2D 的简洁是克制出来的,Bullet 的强大是堆叠出来的。没人会在 2D 游戏里硬接 Bullet,也没人用 Box2D 做《地平线:西部禁域》那种载具+布料+地形变形的混合仿真——不是做不到,是绕路修桥的成本远超收益。



















