Search code examples
javascript3dhtml5-canvascontrolsgame-physics

First person WASD controls


I'm currently developing a 3d game and I'd like to implement a kind of first-person control using the wasd-keys.

My snippet below includes velocity, position and rotation where rotation stands for a value between 0 and 2*Math.PI.

My question how to update my code to use the w-key to go "straight" based on the current rotation, the d key to go back no matter where I'm facing to, and so on.

I believe you got an idea what my problem is - I need some kind of approach how to implement acceleration!

Any help would be really appreciated.

let speed = 0.01,
  maxSpeed = 0.01,
  friction = 0.91

let position = {
    x: 0,
    y: 0,
    z: 0
  },
  velocity = {
    x: 0,
    y: 0,
    z: 0
  },
  rotation = 0;


let update = () => {
  if (keyPressed("w") && velocity.z > -maxSpeed) velocity.z -= speed
  if (keyPressed("s") && velocity.z < maxSpeed) velocity.z += speed
  if (keyPressed("a") && velocity.x > -maxSpeed) velocity.x -= speed
  if (keyPressed("d") && velocity.x < maxSpeed) velocity.x += speed

  velocity.z *= friction
  velocity.x *= friction

  position.z += velocity.z * Math.sin(rotation) // this is
  position.x += velocity.x * Math.sin(rotation) // not working
}


Solution

  • Here is fixed version:

    position.z += velocity.z * Math.cos(rotation);
    position.x += velocity.z * Math.sin(rotation); 
    position.z -= velocity.x * Math.sin(rotation); 
    position.x += velocity.x * Math.cos(rotation);
    

    Click into snippet to transfer focus and then use WSAD keys

    enter image description here

    <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/104/three.min.js">
    </script><script>
    var scene = new THREE.Scene();
    var camera = new THREE.PerspectiveCamera(75,innerWidth / innerHeight,0.01,1000);
    camera.position.set(0, 3, 0);
    var renderer = new THREE.WebGLRenderer();
    renderer.setSize(innerWidth, innerHeight);
    document.body.appendChild(renderer.domElement);
    scene.add(new THREE.GridHelper(500, 100, 0x666666, 0x444444));
    
    let speed = 0.1, maxSpeed = 0.1, friction = 0.91, 
        position = { x: 0, y: 0, z: 0 },
        velocity = { x: 0, y: 0, z: 0 },
        rotation = 0, keyPressed = {};
    
    let update = () => {
        if (keyPressed["w"] && velocity.z > -maxSpeed) velocity.z -= speed;
        if (keyPressed["s"] && velocity.z < maxSpeed) velocity.z += speed;
        if (keyPressed["a"] && velocity.x > -maxSpeed) velocity.x -= speed;
        if (keyPressed["d"] && velocity.x < maxSpeed) velocity.x += speed;
        velocity.z *= friction;
        velocity.x *= friction;
        position.z += velocity.z * Math.cos(rotation);
        position.x += velocity.z * Math.sin(rotation); 
        position.z -= velocity.x * Math.sin(rotation); 
        position.x += velocity.x * Math.cos(rotation);
    };
    
    setInterval(update, 10);
    requestAnimationFrame(render);
    addEventListener('keydown', e => keyPressed[e.key] = true)
    addEventListener('keyup', e => keyPressed[e.key] = false)
    addEventListener('mousemove', e => rotation = e.x*Math.PI*2/innerWidth)
    addEventListener('resize', e => renderer.setSize(innerWidth, innerHeight))  
    
    function render() {
        camera.rotation.y = rotation;
        camera.position.x = position.x;
        camera.position.z = position.z;
        requestAnimationFrame(render);
        renderer.render(scene, camera);
    }
    </script>
    <style>body,canvas{overflow:hidden;margin:0;}</style>