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

基于three.js与Ammo.js使用nipplejs屏幕摇杆无法移动物体求助

问题修复方案

核心问题排查

  • 刚体质量配置错误:你设置的mass = 0在Ammo.js中代表静态刚体,物理引擎默认禁止静态刚体位移,自然无法被驱动。
  • 位移逻辑不符合物理引擎规则:你直接修改Three.js网格player的position属性,接入物理引擎后物体位移由刚体控制,直接修改网格位置会被物理引擎的刚体状态覆盖,不会生效。
  • 更新函数未执行:你定义了updatePlayer但没有注入全局渲染/物理步进循环,函数从未被调用,不会产生位移。
  • 碰撞盒参数错误:btBoxShape构造要求传入半边长,你直接传入完整缩放值,会导致碰撞盒尺寸是网格的2倍,后续会出现碰撞偏移问题。
  • 移动速度过慢:nipplejs返回的vector数值范围是0-1,直接作为位移增量每帧移动距离极小,肉眼很难感知到变化。

具体修改步骤

  1. 修改刚体质量,同时将刚体挂载到player对象方便调用,初始化transform和player位置保持一致:
// 把原来的let mass = 0 改成
let mass = 1;
// 初始化transform时和player位置对齐
transform.setOrigin( new Ammo.btVector3( 0, 5, 0 ) );
// 创建完rigidbody后挂载到player
player.userData.rigidBody = body;
// 激活刚体避免进入休眠状态
body.setActivationState(4);
  1. 修改updatePlayer内的位移逻辑,改为对刚体施加速度,同时同步刚体状态到渲染网格:
const moveSpeed = 10; // 可自行调整移动速度
function updatePlayer(){
  const angle = controls.getAzimuthalAngle();
  let velocityX = 0, velocityZ = 0;

  if (fwdValue > 0) velocityZ -= fwdValue * moveSpeed;
  if (bkdValue > 0) velocityZ += bkdValue * moveSpeed;
  if (lftValue > 0) velocityX -= lftValue * moveSpeed;
  if (rgtValue > 0) velocityX += rgtValue * moveSpeed;

  // 根据相机角度转换移动方向
  tempVector.set(velocityX, 0, velocityZ).applyAxisAngle(upVector, angle);
  // 给刚体设置速度,保留Y轴速度实现重力效果
  const rigidBody = player.userData.rigidBody;
  const currentVelocity = rigidBody.getLinearVelocity();
  rigidBody.setLinearVelocity(new Ammo.btVector3(
    tempVector.x,
    currentVelocity.y(),
    tempVector.z
  ));

  // 同步刚体位置到渲染网格
  let transform = new Ammo.btTransform();
  rigidBody.getMotionState().getWorldTransform(transform);
  const origin = transform.getOrigin();
  const rotation = transform.getRotation();
  player.position.set(origin.x(), origin.y(), origin.z());
  player.quaternion.set(rotation.x(), rotation.y(), rotation.z(), rotation.w());
  
  player.updateMatrixWorld();
  // 原有相机跟随逻辑保留
  camera.position.sub(controls.target);
  controls.target.copy(player.position);
  camera.position.add(player.position);
}
  1. 将updatePlayer注入你的全局渲染循环,保证每帧执行:
function animate() {
  requestAnimationFrame(animate);
  // 原有物理步进逻辑保留
  physicsWorld.stepSimulation(1 / 60, 10);
  // 新增玩家更新调用
  updatePlayer();
  // 原有渲染逻辑保留
  renderer.render(scene, camera);
}
animate();
  1. 修正碰撞盒尺寸:
// 把原来的let colShape = new Ammo.btBoxShape( new Ammo.btVector3( scale.x , scale.y , scale.z  ) ); 改成
let colShape = new Ammo.btBoxShape( new Ammo.btVector3( scale.x / 2 , scale.y / 2 , scale.z / 2  ) );

内容的提问来源于stack exchange,提问作者It's Joker

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 16:36:03