无法使用带有三个 js 和弹药 js 的屏幕操纵杆 (nipplejs) 移动我的对象

Unable to move my object using a onscreen joystick (nipplejs) with three js and ammo js

我正在使用 threejs 和 ammojs 物理引擎制作一个开放世界项目。我正确地完成了所有设置,碰撞工作正常,我面临的唯一问题是我无法用我的操纵杆(来自 nipple js)移动我想要移动的对象。下面是对象和操纵杆控件的以下代码。

function createPlayer() { 
 let pos = {x: 0, y: 0, z: 0};
 let quat = {x: 0, y: 0, z: 0, w: 1};
 let scale = {x: 5, y: 10, z: 5};
 let mass = 0;
 let player = new THREE.Mesh(new THREE.BoxBufferGeometry(), new THREE.MeshBasicMaterial({color: 0x2d2d2d,
 }));
scene.add( player );
player.scale.set(scale.x,scale.y,scale.z);
player.position.set(0,5,0);
player.castShadow = true;
player.receiveShadow = true;

 scene.add(player); 
let transform = new Ammo.btTransform();
                transform.setIdentity();
                transform.setOrigin( new Ammo.btVector3( pos.x, pos.y, pos.z ) );
                transform.setRotation( new Ammo.btQuaternion( quat.x, quat.y, quat.z, quat.w ) );
                let motionState = new Ammo.btDefaultMotionState( transform );

                let colShape = new Ammo.btBoxShape( new Ammo.btVector3( scale.x , scale.y , scale.z  ) );
                colShape.setMargin( 0.05 );

                let localInertia = new Ammo.btVector3( 0, 0, 0 );
                colShape.calculateLocalInertia( mass, localInertia );

                let rbInfo = new Ammo.btRigidBodyConstructionInfo( mass, motionState, colShape, localInertia );
                let body = new Ammo.btRigidBody( rbInfo );


                
                physicsWorld.addRigidBody( body, colGroupPlane, colGroupRedBall );
                
                
let fwdValue = 0;
let bkdValue = 0;
let rgtValue = 0;
let lftValue = 0;
let tempVector = new THREE.Vector3();
let upVector = new THREE.Vector3(0, 1, 0);
let joyManager;

function updatePlayer(){
  // move the player
  const angle = controls.getAzimuthalAngle()
  
    if (fwdValue > 0) {
        tempVector
          .set(0, 0, -fwdValue)
          .applyAxisAngle(upVector, angle)
        player.position.addScaledVector(
          tempVector,
          1
        )
      }
  
      if (bkdValue > 0) {
        tempVector
          .set(0, 0, bkdValue)
          .applyAxisAngle(upVector, angle)
        player.position.addScaledVector(
          tempVector,
          1
        )
      }

      if (lftValue > 0) {
        tempVector
          .set(-lftValue, 0, 0)
          .applyAxisAngle(upVector, angle)
        player.position.addScaledVector(
          tempVector,
          1
        )
      }

      if (rgtValue > 0) {
        tempVector
          .set(rgtValue, 0, 0)
          .applyAxisAngle(upVector, angle)
        player.position.addScaledVector(
          tempVector,
          1
        )
      }
  
  player.updateMatrixWorld()
  
  //controls.target.set( mesh.position.x, mesh.position.y, mesh.position.z );
  // reposition camera
  camera.position.sub(controls.target)
  controls.target.copy(player.position)
  camera.position.add(player.position)
 
}

function addJoystick(){
   const options = {
        zone: document.getElementById('joystickWrapper1'),
        size: 120,
        multitouch: true,
        maxNumberOfNipples: 2,
        mode: 'static',
        restJoystick: true,
        shape: 'circle',
        // position: { top: 20, left: 20 },
        position: { top: '0', left: '0' },
        dynamicPage: true,
      }
   
   
  joyManager = nipplejs.create(options);
  
joyManager['0'].on('move', function (evt, data) {
        const forward = data.vector.y
        const turn = data.vector.x

        if (forward > 0) {
          fwdValue = Math.abs(forward)
          bkdValue = 0
        } else if (forward < 0) {
          fwdValue = 0
          bkdValue = Math.abs(forward)
        }

        if (turn > 0) {
          lftValue = 0
          rgtValue = Math.abs(turn)
        } else if (turn < 0) {
          lftValue = Math.abs(turn)
          rgtValue = 0
        }
      })

     joyManager['0'].on('end', function (evt) {
        bkdValue = 0
        fwdValue = 0
        lftValue = 0
        rgtValue = 0
      })
  
}
addJoystick();
            }
            

对于 Ammo.js 中玩家控制的移动,我发现最好的方法是明确设置线性速度,而不是尝试直接更新位置。

示例见此答案:

您甚至可以再使用一个间接级别,并施加一个力(这将导致加速度并因此产生速度和位置变化),而不是试图直接控制速度或位置。

一般来说,根据我的经验,在使用物理引擎时,使用力 and/or 速度要容易得多,而不是明确设置对象位置。

但是,如果您确实想直接设置位置,这个对同一问题的回答可能会对您有所帮助:

下例中使用设置线速度的方法移动物体是一个球,直接从摇杆上取值,用它来移动球体球

let fwdValue = 0;

let bkdValue = 0;

let rgtValue = 0;

let lftValue = 0;

function moveBall() {

  let scalingFactor = 6;
  
  let moveX = rgtValue - lftValue;
  let moveZ = bkdValue - fwdValue;
  let moveY = 0;

  if (moveX == 0 && moveY == 0 && moveZ == 0) return;

  let resultantImpulse = new Ammo.btVector3(moveX, moveY, moveZ)
  resultantImpulse.op_mul(scalingFactor);

  let physicsBody = ballObject.userData.physicsBody;
  physicsBody.setLinearVelocity(resultantImpulse);

}

问题已解决✔️