You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.27 08:06:03