To easily achieve this, one simple approach is to reparent as follows:
<!-- The default aframe camera entity -->
<a-camera>
<!-- Add an object with the same transform as the camera plus an offset -->
<a-box position="0 0 -0.5"></a-box>
</a-camera>
<script src="https://aframe.io/releases/1.3.0/aframe.min.js"></script>
<a-scene>
<a-box position="-1 0.5 -3" rotation="0 45 0" 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>
<!-- "Player" -->
<a-camera>
<a-box position="0 -0.5 -0.65" scale="0.25 0.25 0.25" color="red"></a-box>
</a-camera>
</a-scene>
A more intricate yet flexible solution involves creating a controller using JavaScript. Let's aim to:
- Have the camera follow the box
- Rotate the box with the camera
- Achieve smooth rather than instant movements
This functionality can be implemented through a component like this:
<script src="https://aframe.io/releases/1.3.0/aframe.min.js"></script>
<script src="https://unpkg.com/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="c3a2afcbb2aeace56aa6aea5b8e1afa3a2b8a4acbd98d9c4d8c4da">[email protected]</a>/dist/aframe-orbit-controls.min.js"></script>
<script>
AFRAME.registerComponent("follow-box", {
schema: {
target: {type: "selector"}
},
tick: (function() {
// Initialize once
const tmpv = new THREE.Vector3();
return function(t, dt) {
if (!this.data.target) return; // Ignore when no target specified
const target = this.data.target.getObject3D("mesh"); // Obtain the mesh
// Track the position
const position = target.getWorldPosition(tmpv); // Get the world position
this.el.object3D.position.lerp(tmpv, 0.5); // Linear interpolation towards the world position
}
})()
})
AFRAME.registerComponent("rotate-with-camera", {
tick: (function() {
// Initialize once
const tmpq = new THREE.Quaternion();
const tmpe = new THREE.Euler();
return function(t, dt) {
if (!this.el.sceneEl.camera) return; // Ignore when no camera available
const cam = this.el.sceneEl.camera.el; // Get the camera entity
cam.object3D.getWorldQuaternion(tmpq); // Get the world rotation
tmpe.setFromQuaterion(tmpq, 'YXZ');
// Setting attributes is necessary for wasd controls
this.el.setAttribute("rotation", {x: 0, y: tmpe.y * 180 / Math.PI, z: 0 });
}
})()
})
</script>
<a-scene>
<a-box position="-1 0.5 -3" rotation="0 45 0" 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>
<!-- Camera "rig" -->
<a-entity follow-box="target: #player" look-controls>
<a-entity camera position="0 1.6 2"></a-entity>
</a-entity>
<!-- The "player" -->
<a-box id="player" color="red" wasd-controls="speed: 35" rotate-with-camera></a-box>
<a-sky color="#ECECEC"></a-sky>
</a-scene>
Check out a live demonstration on Glitch of this concept in action within Aframe networked.
The optimal method would involve leveraging the orbit-controls, though customization might be needed for compatibility with wasd controls.