无法使用带有三个 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);
}
问题已解决✔️
我正在使用 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);
}
问题已解决✔️