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

CannonJS碰撞处理问题:角色盒子与房屋盒子碰撞后异常滑动

解决CannonJS角色碰撞后异常滑动的问题

1. 先把房屋对象(Box2)设为静态体

CannonJS里哪怕质量极大的动态体,也会被外力推动,必须将Box2设为静态体才能完全固定:

const box2Body = new CANNON.Body({
  mass: 0, // 质量为0是标记静态体的核心
  shape: new CANNON.Box(new CANNON.Vec3(1, 1, 1)),
  position: new CANNON.Vec3(0, 0, 0)
});
world.addBody(box2Body);

2. 修正角色(Box1)的移动逻辑

如果是直接设置velocity来控制角色移动,会绕过物理引擎的力计算逻辑,摩擦参数根本无法生效。必须改用**施加力(force)或冲量(impulse)**的方式:

// 方向键施加力示例
document.addEventListener('keydown', (e) => {
  const moveForce = new CANNON.Vec3(0, 0, 0);
  const baseSpeed = 6;
  switch(e.key) {
    case 'ArrowLeft': moveForce.x = -baseSpeed; break;
    case 'ArrowRight': moveForce.x = baseSpeed; break;
    case 'ArrowUp': moveForce.z = -baseSpeed; break;
    case 'ArrowDown': moveForce.z = baseSpeed; break;
  }
  box1Body.applyForce(moveForce, box1Body.position);
});

如果是需要瞬间响应的移动(比如冲刺),可以用冲量替代:

box1Body.applyImpulse(moveForce, box1Body.position);

3. 配置接触材质的摩擦与恢复系数

单独设置单个物体的参数可能不生效,需要给两个物体设置共享的接触材质,强制覆盖碰撞时的物理表现:

// 创建两个物体的材质
const playerMat = new CANNON.Material();
const houseMat = new CANNON.Material();

// 创建接触材质,明确碰撞规则
const contactMat = new CANNON.ContactMaterial(
  playerMat,
  houseMat,
  {
    friction: 1, // 最大摩擦系数,完全阻止滑动
    restitution: 0 // 恢复系数设为0,碰撞后完全不反弹
  }
);

// 绑定材质到物体并添加到物理世界
box1Body.material = playerMat;
box2Body.material = houseMat;
world.addContactMaterial(contactMat);

4. 启用物体睡眠机制

开启睡眠可以让静止的角色停止物理计算,避免微小残留力导致的滑动:

box1Body.sleepSpeedLimit = 0.1; // 速度低于该值时触发睡眠检测
box1Body.sleepTimeLimit = 0.3; // 持续低速超过该时间进入睡眠状态

5. 检查物理世界全局参数

确保物理世界的默认配置没有拖后腿:

const world = new CANNON.World();
world.gravity.set(0, -9.82, 0);
world.defaultContactMaterial.friction = 1; // 全局默认摩擦
world.defaultContactMaterial.restitution = 0; // 全局默认无反弹

内容的提问来源于stack exchange,提问作者Gaurav Sharma

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 17:08:22