There are various ways to approach this problem.
0) Utilizing Vectors
A straightforward method commonly found in most 3D engines:
- Retrieve the camera's forward vector / world direction
- Scale it by the desired distance for movement
- Add it to your position vector
To implement the above steps within an A-Frame component, consider the following example:
<script src="https://aframe.io/releases/1.2.0/aframe.min.js"></script>
<script>
// defining a custom component
AFRAME.registerComponent("foo", {
init: function() {
// accessing the camera
var player = document.querySelector("a-camera")
// creating a directional vector
var direction = new THREE.Vector3();
window.addEventListener("keydown", (e) => {
if (e.code === "KeyR") {
// retrieving the camera's world direction
this.el.sceneEl.camera.getWorldDirection(direction);
// scaling the direction by a "speed" factor
direction.multiplyScalar(0.1)
// obtaining the current position
var pos = player.getAttribute("position")
// adding the directional vector
pos.add(direction)
// setting the new position
player.setAttribute("position", pos);
}
})
}
})
</script>
<a-scene>
<a-box position="-1 0.5 -3" rotation="0 45 0" foo color="#4CC3D9"></a-box>
<a-sphere position="0 1.25 -5" radius="1.25" color="#EF2D5E"></a-sphere>
<a-cylinder position="1 0.75 -3" radius="0.5" height="1.5" color="#FFC65D"></a-cylinder>
<a-plane position="0 0 -4" rotation="-90 0 0" width="4" height="4" color="#7BC8A4"></a-plane>
<a-sky color="#ECECEC"></a-sky>
<a-camera></a-camera>
</a-scene>
However, if you prefer a more mathematical approach:
1) Delving into 2D Polar Coordinates
The mapping of angles to 2D space is where the polar coordinate system comes in handy!
To calculate x and y coordinates based on camera rotation, use the following conversion formulae:
x = r * cos(a)
y = r * sin(a)
Here, "r" represents the step, and "a" denotes the angle.
Let's put theory into action with this snippet:
var angle = player.getAttribute("rotation")
var x = 1 * Math.cos(angle.y * Math.PI / 180)
var y = 1 * Math.sin(angle.y * Math.PI / 180)
var pos = player.getAttribute("position")
pos.x -= y;
pos.z -= x;
player.setAttribute("position", pos);
In essence, obtain the angle, calculate the shift, and update the position accordingly.
We can adapt the previous example as follows:
<script src="https://aframe.io/releases/1.2.0/aframe.min.js"></script>
<script>
AFRAME.registerComponent("foo", {
init: function() {
var player = document.querySelector("a-camera")
window.addEventListener("keydown", (e) => {
if (e.code === "KeyR") {
var angle = player.getAttribute("rotation")
var x = 0.1 * Math.cos(angle.y * Math.PI / 180)
var y = 0.1 * Math.sin(angle.y * Math.PI / 180)
var pos = player.getAttribute("position")
pos.x -= y;
pos.z -= x;
player.setAttribute("position", pos);
}
})
}
})
</script>
<a-scene>
<a-box position="-1 0.5 -3" rotation="0 45 0" foo color="#4CC3D9"></a-box>
<a-sphere position="0 1.25 -5" radius="1.25" color="#EF2D5E"></a-sphere>
<a-cylinder position="1 0.75 -3" radius="0.5" height="1.5" color="#FFC65D"></a-cylinder>
<a-plane position="0 0 -4" rotation="-90 0 0" width="4" height="4" color="#7BC8A4"></a-plane>
<a-sky color="#ECECEC"></a-sky>
<a-camera></a-camera>
</a-scene>
2) Venturing into 3D Spherical Coordinates
We're dealing with a 3D environment after all.
The idea remains consistent - converting camera angles into x/y/z coordinates. The ingenious twist here lies in leveraging conversions from the spherical coordinate system. Although three dimensions add complexity, one critical difference is the axis orientation between spherical and clipspace (utilized by A-Frame):
https://i.sstatic.net/V7LGJ.png
Taking this into account, calculations should align with this code snippet:
<script src="https://aframe.io/releases/1.2.0/aframe.min.js"></script>
<script>
// same logic as 2D but different computations
AFRAME.registerComponent("foo", {
init: function() {
var player = document.querySelector("a-camera")
window.addEventListener("keydown", (e) => {
if (e.code === "KeyR") {
// accessing player rotation
var angle = player.getAttribute("rotation")
// calculating angles
let theta = (angle.x * Math.PI / 180) + Math.PI / 2
let fi = angle.y * Math.PI / 180
let r = 0.1
// computing shifts in position
let z = Math.sin(theta) * Math.cos(fi) * r
let x = Math.sin(theta) * Math.sin(fi) * r
let y = Math.cos(theta) * r
// updating position
var pos = player.getAttribute("position")
pos.x -= x;
pos.y -= y;
pos.z -= z;
player.setAttribute("position", pos);
}
})
}
})
</script>
<a-scene>
<a-box position="-1 0.5 -3" rotation="0 45 0" foo color="#4CC3D9"></a-box>
<a-sphere position="0 1.25 -5" radius="1.25" color="#EF2D5E"></a-sphere>
<a-cylinder position="1 0.75 -3" radius="0.5" height="1.5" color="#FFC65D"></a-cylinder>
<a-plane position="0 0 -4" rotation="-90 0 0" width="4" height="4" color="#7BC8A4"></a-plane>
<a-sky color="#ECECEC"></a-sky>
<a-camera></a-camera>
</a-scene>