如何使用Cannon.js+Three.js实现物体跳跃并解决静止无法起跳问题
Cannon.js + Three.js 跳跃失效问题解决方案
静止状态下直接修改cannonBody.velocity.y无法触发跳跃的核心原因是:Cannon.js默认开启了刚体休眠优化,当刚体速度低于内置阈值、持续静止一段时间后,会自动进入休眠状态以减少性能开销,此时对速度、位置的修改不会被物理引擎计算,因此没有跳跃效果。
正常跳跃的前置条件
- 确保刚体未处于休眠状态:要么初始化刚体时设置
allowSleep: false关闭自动休眠(适合操作频繁的可交互物体),要么修改速度前手动调用cannonBody.wakeUp()唤醒刚体 - 实现地面碰撞校验:仅当刚体与底部可站立接触面发生碰撞时才允许触发跳跃,避免空中重复跳跃
- 速度直接赋值而非叠加:直接覆盖
velocity.y的值,不要用累加的方式,避免物体在斜面、移动状态下跳跃高度异常 - 物理修改放在主循环执行:不要在
collide事件回调内直接修改速度,回调中的物理状态可能被引擎帧逻辑覆盖,建议把跳跃标记放在碰撞回调中,在物理帧更新逻辑中统一处理跳跃逻辑
空格键控制小球跳跃演示代码
// 基础参数配置 const JUMP_VELOCITY = 8; let canJump = false; // 初始化Cannon小球刚体 const sphereShape = new CANNON.Sphere(1); const sphereBody = new CANNON.Body({ mass: 1, shape: sphereShape, position: new CANNON.Vec3(0, 5, 0), // 关闭自动休眠,避免静止后修改速度失效 allowSleep: false }); world.addBody(sphereBody); // 碰撞监听,标记可跳跃状态 sphereBody.addEventListener('collide', (event) => { // 碰撞法线y值大于0.5说明是接触到底部的站立面 const contactNormal = event.contact.ni; if (contactNormal.y > 0.5) { canJump = true; } }); // 空格键跳跃监听 document.addEventListener('keydown', (e) => { if (e.code === 'Space' && canJump) { // 若未关闭allowSleep,需先调用唤醒方法 // sphereBody.wakeUp(); sphereBody.velocity.y = JUMP_VELOCITY; canJump = false; } }); // 渲染循环中同步物理状态到Three.js模型 function animate() { requestAnimationFrame(animate); // 步进物理世界 world.step(1 / 60); // 同步小球模型的位置和旋转 sphereMesh.position.copy(sphereBody.position); sphereMesh.quaternion.copy(sphereBody.quaternion); renderer.render(scene, camera); } animate();
内容的提问来源于stack exchange,提问作者Hari
相关产品推荐
相关产品推荐

