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

Three.js+Ammo.js FPS模式玩家左右移动异常问题求助

问题描述

为玩家(相机)绑定物理体后,前后移动功能正常,但左右移动始终异常。不想使用常规的运动学控制容器,希望让图形对象跟随物理体运动。核心代码如下:

if (this.moveForward == true) {
  // WORKS PERFECT IN ANY DIRECTION
  this.pos.copy(this.raycaster.ray.direction);
  this.pos.multiplyScalar(12);
  this.playerBody.userData.physicsBody.setLinearVelocity(
    new Ammo.btVector3(this.pos.x,this.pos.y,this.pos.z));
} else if (this.moveBackward == true) {
  // WORKS PERFECT IN ANY DIRECTION
  this.pos.copy(this.raycaster.ray.direction);
  this.pos.multiplyScalar(12);
  this.playerBody.userData.physicsBody.setLinearVelocity(
    new Ammo.btVector3(-this.pos.x,this.pos.y,-this.pos.z));
} else if (this.moveLeft == true) {
  // NOT WORKS PERFECT IN ANY DIRECTION !!!!
  this.pos.copy(this.raycaster.ray.direction);
  this.pos.multiplyScalar(12);
  this.playerBody.userData.physicsBody.setLinearVelocity(
    new Ammo.btVector3(this.pos.x, 0, this.pos.y));
 } else if (this.moveRight == true) {
  // NOT WORKS PERFECT IN ANY DIRECTION !!!!
  this.pos.copy(this.raycaster.ray.direction);
  this.pos.multiplyScalar(12);
  this.playerBody.userData.physicsBody.setLinearVelocity(
    new Ammo.btVector3(-this.pos.y,  0, -this.pos.x));
 }

尝试过多种x、y、z正负组合调整,均未解决问题。需要修改this.raycaster.ray.direction(例如绕Y轴旋转±90度),使左右移动效果和前后移动一致。

解决方案

问题出在左右移动时未正确计算相机的水平侧方方向。前后移动用的是相机前向向量(raycaster.ray.direction),左右移动需要将前向向量绕Y轴旋转90度得到侧方向量,同时要保证移动仅在水平面上进行(忽略Y轴分量)。

修改后的完整代码如下:

// 定义临时向量用于计算侧方方向
const sideDir = new THREE.Vector3();

if (this.moveForward == true) {
  this.pos.copy(this.raycaster.ray.direction);
  this.pos.multiplyScalar(12);
  this.playerBody.userData.physicsBody.setLinearVelocity(
    new Ammo.btVector3(this.pos.x, this.pos.y, this.pos.z));
} else if (this.moveBackward == true) {
  this.pos.copy(this.raycaster.ray.direction);
  this.pos.multiplyScalar(12);
  this.playerBody.userData.physicsBody.setLinearVelocity(
    new Ammo.btVector3(-this.pos.x, this.pos.y, -this.pos.z));
} else if (this.moveLeft == true) {
  // 计算左方向:前向向量去Y分量后绕Y轴旋转90度
  sideDir.copy(this.raycaster.ray.direction);
  sideDir.y = 0; // 仅保留水平方向
  sideDir.normalize(); // 归一化避免斜向移动速度异常
  // 左手坐标系下绕Y轴转90度得到左方向
  const tempX = sideDir.x;
  sideDir.x = -sideDir.z;
  sideDir.z = tempX;
  
  sideDir.multiplyScalar(12);
  this.playerBody.userData.physicsBody.setLinearVelocity(
    new Ammo.btVector3(sideDir.x, 0, sideDir.z));
} else if (this.moveRight == true) {
  // 计算右方向:前向向量去Y分量后绕Y轴旋转-90度
  sideDir.copy(this.raycaster.ray.direction);
  sideDir.y = 0;
  sideDir.normalize();
  // 左手坐标系下绕Y轴转-90度得到右方向
  const tempX = sideDir.x;
  sideDir.x = sideDir.z;
  sideDir.z = -tempX;
  
  sideDir.multiplyScalar(12);
  this.playerBody.userData.physicsBody.setLinearVelocity(
    new Ammo.btVector3(sideDir.x, 0, sideDir.z));
}

关键细节说明

  • 去除Y轴分量:确保左右移动是纯水平的,不会出现上下偏移。
  • 归一化向量:避免相机抬头/低头时,侧方向量长度变化导致移动速度忽快忽慢。
  • 旋转方向适配:代码采用Three.js默认的左手坐标系,若使用右手坐标系,需调整旋转公式的正负号(比如左方向改为(x, z) → (z, -x))。

内容的提问来源于stack exchange,提问作者Nikola Lukic

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 05:03:36