Tengo un modelo gltf de mi robot cargado en A-frame scene versión 1.0.4. Hasta ahora, puedo girar el robot sobre sus ejes x, y, z, pero cuando trato de moverlo hacia adelante, todavía se mueve en su dirección inicial en lugar de en la dirección en la que mira. Quiero poder controlar sus movimientos con mi teclado sin usar bibliotecas externas. Creo que tengo que usar Quaternions, pero aún no he descubierto cómo usarlos. Aquí está mi código de marco A hasta ahora.
<a-scene id="myScene"> <a-entity environment="preset:forest;"></a-entity> <a-entity gltf-model="#humanoid" id="robot" position="0 20 0" rotation="0 0 0" scale="0.0001 0.0001 0.0001" static-body> </a-entity> </a-scene>Y aquí está mi guión
const robot = document.getElementById('robot'); const update = () => { if (keys.forward) { let {x,y,z} = robot.object3D.position; let ry = robot.object3D.rotation.y; z += Math.cos(ry * Math.PI/180)/12; x += Math.sin(ry * Math.PI/180)/12; robot.object3D.position.set(x, y, z); } else if (keys.backwards) { let {x, y, z} = robot.object3D.position; let ry = robot.object3D.rotation.y; z -= Math.cos(ry * Math.PI/180)/10; x -= Math.sin(ry * Math.PI/180)/10; robot.object3D.position.set(x, y, z); } if (keys.turnLeft) { let {x, y, z} = robot.getAttribute('rotation'); y += 0.25; robot.setAttribute('rotation',{x,y,z}); } else if (keys.turnRight) { let {x, y, z} = robot.getAttribute('rotation'); y -= 0.25; robot.setAttribute('rotation',{x,y,z}); } }Sí, usar cuateniones es una buena manera de resolver esto.
Simplemente puede aplicar el cuaternión actual del robot a un vector3 que represente el movimiento que desea realizar en la rotación original del robot y aplicarlo a la posición del robot.
Algo como esto:
fowardVector = new Vector3(0, 0, -0.1) rotatedForwardVector = new Vector3(); rotatedForwardVector.copy(forwardVector); rotatedForwardVector.applyQuaternion(robot.object3D.quaternion); robot.object3D.position.add(rotatedForwardVector);Tenga en cuenta que solo querrá crear los Vector3 una vez y luego reutilizarlos para evitar la recolección de basura innecesaria, en lugar de crearlos para cada movimiento.
Por ejemplo, usando un cierre como se explica aquí
let ry = robot.object3D.rotation.y; z += Math.cos(ry * Math.PI/180)/12;
Aunque a-frame usa grados para la rotación, threejs usa radianes, por lo que no es necesario volver a convertirlos:
const robot = document.querySelector("a-box") document.body.addEventListener("keydown", (evt) => { if (evt.key === 's') { let {x,y,z} = robot.object3D.position; let ry = robot.object3D.rotation.y; z += Math.cos(ry)/12; x += Math.sin(ry)/12; robot.object3D.position.set(x, y, z); } else if (evt.key === 'w') { let {x, y, z} = robot.object3D.position; let ry = robot.object3D.rotation.y; console.log(ry) z -= Math.cos(ry)/10; x -= Math.sin(ry)/10; robot.object3D.position.set(x, y, z); } if (evt.key === 'a') { let {x, y, z} = robot.getAttribute('rotation'); y += 1; robot.setAttribute('rotation',{x,y,z}); } else if (evt.key === 'd') { let {x, y, z} = robot.getAttribute('rotation'); y -= 1; robot.setAttribute('rotation',{x: x,y: y,z: z}); } }) <script src="https://aframe.io/releases/1.3.0/aframe.min.js"></script> <a-scene> <a-box position="-1 0.5 -3" rotation="0 0 0" color="#4CC3D9"> <a-sphere radius="0.5" position="0 0 -1"></a-sphere> </a-box> <a-entity camera position="0 1.6 0"></a-entity> </a-scene> Lo mismo con getWorldDirection :
const robot = document.querySelector("a-box") const direction = new THREE.Vector3(); document.body.addEventListener("keydown", (evt) => { if (evt.key === 's') { // get robot direction robot.object3D.getWorldDirection(direction); // add a "speed" value direction.multiplyScalar(0.1) // add the new vector to the actual position robot.object3D.position.add(direction) } else if (evt.key === 'w') { robot.object3D.getWorldDirection(direction); direction.multiplyScalar(-0.1) robot.object3D.position.add(direction) } if (evt.key === 'a') { let {x, y, z} = robot.getAttribute('rotation'); y=y+1 robot.setAttribute('rotation',{x,y,z}); } else if (evt.key === 'd') { let {x, y, z} = robot.getAttribute('rotation'); y=y-1 robot.setAttribute('rotation',{x: x,y: y,z: z}); } }) <script src="https://aframe.io/releases/1.3.0/aframe.min.js"></script> <a-scene> <a-box position="-1 0.5 -3" rotation="0 0 0" color="#4CC3D9"> <a-sphere radius="0.5" position="0 0 -1"></a-sphere> </a-box> <a-entity camera position="0 1.6 0"></a-entity> </a-scene>Puede usar Quaternions y muchas otras formas, pero Object3D tiene algunas alternativas útiles y más simples para mover objetos en coordenadas locales:
Creo que el más simple es usar https://threejs.org/docs/#api/en/core/Object3D.translateZ
robot.object3D.translateZ(amountToMoveForward);También se puede usar https://threejs.org/docs/#api/en/core/Object3D.localToWorld para transformar vectores.