Reputation: 21
I'm writing a top down game with Three.js
with single square movement like Frogger
or other classic arcade games. I'm struggling with keeping the camera centered on the main character when it moves. Right now I'm using MapControls.js
for key controls, but panning moves the camera by a certain number of pixels, and the character moves by setting it's position +-10 in z
or x
directions, and they don't always match up, so by the time you reach the end of the board in one direction, the character is almost off of the screen and the camera has moved too far. Can I attach the camera looking down the y-axis somehow while still keeping the pan effect on move?
Upvotes: 2
Views: 4962
Reputation:
Why not just copy the player's x and z to the camera's? Or, copy a portion every frame.
camera.position.lerp(player.position, 0.03);
Example. Run it, click on it, then use the arrow keys
'use strict';
/* global THREE */
function main() {
const canvas = document.querySelector('#c');
const renderer = new THREE.WebGLRenderer({canvas: canvas});
const fov = 45;
const aspect = 2; // the canvas default
const near = 0.1;
const far = 100;
const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
// make the camera look down
camera.position.set(0, 10, 0);
camera.up.set(0, 0, -1);
camera.lookAt(0, 0, 0);
const scene = new THREE.Scene();
scene.background = new THREE.Color('black');
scene.add(new THREE.GridHelper(40, 40));
let player;
{
const cubeSize = 1;
const cubeGeo = new THREE.BoxBufferGeometry(cubeSize, cubeSize, cubeSize);
const cubeMat = new THREE.MeshBasicMaterial({color: 'red'});
player = new THREE.Mesh(cubeGeo, cubeMat);
player.position.set(.5, .5, .5);
scene.add(player);
}
function resizeRendererToDisplaySize(renderer) {
const canvas = renderer.domElement;
const width = canvas.clientWidth;
const height = canvas.clientHeight;
const needResize = canvas.width !== width || canvas.height !== height;
if (needResize) {
renderer.setSize(width, height, false);
}
return needResize;
}
function render() {
if (resizeRendererToDisplaySize(renderer)) {
const canvas = renderer.domElement;
camera.aspect = canvas.clientWidth / canvas.clientHeight;
camera.updateProjectionMatrix();
}
camera.position.lerp(player.position, 0.03);
camera.position.y = 10; // keep the elevation;
renderer.render(scene, camera);
requestAnimationFrame(render);
}
requestAnimationFrame(render);
window.addEventListener('keydown', (e) => {
e.preventDefault();
switch (e.keyCode) {
case 38: // up
player.position.z -= 1;
break;
case 40: // down
player.position.z += 1;
break;
case 37: // left
player.position.x -= 1;
break;
case 39: // right
player.position.x += 1;
break;
}
});
}
main();
html, body {
margin: 0;
height: 100%;
}
#c {
width: 100%;
height: 100%;
display: block;
}
<canvas id="c"></canvas>
<script src="https://threejsfundamentals.org/threejs/resources/threejs/r98/three.min.js"></script>
Increase the 0.03 to a large number to make the camera catch up faster.
Upvotes: 7