基于three.js与Ammo.js使用nipplejs屏幕摇杆无法移动物体求助
问题修复方案
核心问题排查
- 刚体质量配置错误:你设置的
mass = 0在Ammo.js中代表静态刚体,物理引擎默认禁止静态刚体位移,自然无法被驱动。 - 位移逻辑不符合物理引擎规则:你直接修改Three.js网格
player的position属性,接入物理引擎后物体位移由刚体控制,直接修改网格位置会被物理引擎的刚体状态覆盖,不会生效。 - 更新函数未执行:你定义了
updatePlayer但没有注入全局渲染/物理步进循环,函数从未被调用,不会产生位移。 - 碰撞盒参数错误:
btBoxShape构造要求传入半边长,你直接传入完整缩放值,会导致碰撞盒尺寸是网格的2倍,后续会出现碰撞偏移问题。 - 移动速度过慢:nipplejs返回的vector数值范围是0-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);
- 修改
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); }
- 将
updatePlayer注入你的全局渲染循环,保证每帧执行:
function animate() { requestAnimationFrame(animate); // 原有物理步进逻辑保留 physicsWorld.stepSimulation(1 / 60, 10); // 新增玩家更新调用 updatePlayer(); // 原有渲染逻辑保留 renderer.render(scene, camera); } animate();
- 修正碰撞盒尺寸:
// 把原来的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
相关产品推荐
相关产品推荐

