直接调用 ammo.js
rigidbody、collision 和 joint 组件覆盖大多数游戏需求,但 Bullet 提供的功能更多。可以直接调用 ammo.js 使用连续碰撞检测、自定义碰撞标志、其他约束、软体和车辆。
ammo.js 直接移植 Bullet,因此 API 与 C++ 对应。虽然没有独立 ammo.js 文档,但 Bullet 用户手册适用,JavaScript 暴露的类和方法列在仓库的 ammo.idl 中。编辑器从商店导入及引擎示例提供的构建包含该文件全部接口。如需更多功能,可自行编译并替换;编辑器中作为 WASM 模块资源添加。
注意
直接使用 Ammo 会绕过引擎组件,将项目绑定到 ammo.js 后端,不属于 PlayCanvas API 参考覆盖范围;相关对象也属于引擎内部,版本间可能变化。组件能够满足需求时,应优先使用组件。
访问原生对象
每个 rigidbody 包装一个 Bullet btRigidBody,组件初始化后通过 entity.rigidbody.body 访问。整个模拟位于 btDiscreteDynamicsWorld,通过 app.systems.rigidbody.dynamicsWorld 访问。ammo.js 未加载时,两者为 null。各开发方式属性相同,实体和应用的获取方式见移动刚体。
保持 ammo.js 代码稳定的两个规则:
- **使用时再取刚体。**修改类型或碰撞形状等属性时,引擎会重建原生刚体,因此不要跨帧缓存
rigidbody.body。每次使用时重新读取,变化后重新应用自定义设置。 - **释放自己分配的对象。**ammo.js 对象位于 WebAssembly 内存,不由 JavaScript 垃圾回收管理。创建的
btVector3、btTransform或约束用完后,调用Ammo.destroy()。
连续碰撞检测
高速刚体有时会互相穿透。Bullet 的连续碰撞检测(CCD)通过在刚体前后位置间扫掠球体,检查沿途交点,补充常规检测。rigidbody 组件未暴露 CCD,但可通过原生刚体上的两个调用启用:
// Run this once the body exists, for example in a script's initialize(), and again
// if the body is recreated by a change of type or shape
const body = entity.rigidbody.body;
// Distance in meters the body must move in one step before CCD kicks in
body.setCcdMotionThreshold(1);
// Radius of the swept sphere. Keep it below the half extent of the shape:
// for an object about 1 meter across, try 0.2
body.setCcdSweptSphereRadius(0.2);
扩展内置组件之外的功能
同样的方法也可用于其他 Bullet 功能:
- 约束。关节组件支持固定、球形、铰链、滑块和 6dof。其他类型或参数可自行创建 Bullet 约束,通过
addConstraint()加入物理世界,结束时移除并销毁。Physics Constraints 项目以此方式驱动全部 Bullet 约束类型。 - **车辆。**Bullet 射线车辆在底盘刚体上模拟车轮、悬挂和转向。没有专门车辆组件,因此车辆物理教程和引擎 vehicle.js 直接控制
btRaycastVehicle。 - **软体和布料。**ammo.js 包含 Bullet 软体求解器,但需要软刚体世界,而非引擎默认离散世界,属于较高级集成。
车辆
另请参阅
- CCD 物理:将 CCD 封装为可配置脚本。
- 车辆物理:在桌面、移动和 WebXR 中驾驶射线车辆。
- 关节:不直接接触 ammo.js 也能使用的约束。
- ammo.js 替代方案:其他引擎及后端接口。
- Bullet 用户手册:适用于 ammo.js 的文档。