← back to the writings

First person navigation with threeJS

Posted on September 9th, 2015 in Tutorials by Graeme

This tutorial will show you how to navigate through a 3D environment using your keyboard's arrows, much like a first person shooter game such as Doom (or Halo these days). To achieve this, you'll need three things:

  1. A surface to navigate along - use planeGeometry or follow this guide to set up a fancier terrain
  2. The ThreeX.Keyboardstate script by Jerome Etienne
  3. Some music - this is just for you to enjoy following the tutorial more

 Step 1: Include the ThreeX.Keyboardstate Script

An easy first step - just include the ThreeX.Keyboardstate script underneath the main three.js script:

  <script src="libs/three.js"></script>
  <script src="libs/THREEx.KeyboardState.js"></script> 

Step 2: Create a skeleton Camera Control Object

Using the combination/constructor prototype pattern (a way of writing object oriented JavaScript), create a Camera Controls object:

   * CameraControls
  function CameraControls(){


Above is the basic structure for our CameraControl object:

  • In line 4, we define create the constructor for the CameraControls object.
  • In line 8, we add the constructor to the CameraControls object 

Now inside the prototype declaration, we can add a function called 'update' which will contain all the code related to moving the camera around the world:


    update:function(camera, keyboard, clock){
      //functionality to go here


Line 4 shows the new update function, which has camera, keyboard and clock variables:

  • It's obvious what the camera is
  • Keyboard will be a ThreeX.Keyboardstate instance

Now your set up, and we can start adding in the main functionality to control the camera position.

Step 3: Move the camera using ThreeX.Keyboardstate

Inside the update function created in the previous step, we'll add all the code to move the camera about - using the ThreeX.Keyboardstate script included in step 1.

To start, define 3 variables at the top of the update function:

var delta = clock.getDelta(); // seconds.
var moveDistance = 150 * delta; // 200 pixels per second
var rotateAngle = Math.PI / 2 * delta;   // pi/2 radians (90 degrees) per second

What are these for?

  • delta uses the clock instance passed into the update function - it is used to define the speed in moveDistance and rotateAngle
  • moveDistance defines how many pixels the camera will move per second when a direction key is pressed
  • rotateAngle does the same as moveDistance, but for rotating left and right

Now we can move onto hooking up the keyboard presses with the camera.  Keep in mind that in the following codeblock, keyboard is a ThreeX.Keyboardstate object passed into the update function, so has some awesome functionality. The keyboard (ThreeX.Keyboardstate instance) object has a pressed() function, which accepts any key on the keyboard as a parameter. Therefore, to detect if the up arrow is being pressed, we can pass in "up":

if ( keyboard.pressed("up") ){
    //if up is pressed, move the camera into the screen
    camera.translateZ( -moveDistance );

Above, we use the translateZ function available to the camera object, and move the camera into the screen (away from you) by providing a negative moveDistance value.

That's actually as complicated as it gets - implementations of the other arrow key presses can be seen below. Left and right rotate the camera rather than move it:

// move forwards/backwards/left/right
if ( keyboard.pressed("up") )
    		camera.translateZ( -moveDistance );
if ( keyboard.pressed("down") )
    		camera.translateZ(  moveDistance );
// rotate left/right
if ( keyboard.pressed("left") )
    camera.rotateOnAxis( new THREE.Vector3(0,1,0), rotateAngle);
if ( keyboard.pressed("right") )
    camera.rotateOnAxis( new THREE.Vector3(0,1,0), -rotateAngle);

Step 4: Use the CameraControls object in your main script

To actually use the object created in the previous steps, you first have to create an instance of it:

var cameraControls = new CameraControls();

Then, create the keyboard instance (along with clock and camera):

var keyboard = new THREEx.KeyboardState();
var clock = new THREE.Clock();
var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 1000);

And finally use the update function we created in the render function of your main three.js script:


Well Done

Congrats, you're done - if there's any questions/improvements please add them in the comments.


Have any thoughts?