Basic Threejs Game Tutorial Part 4: Moving 2


In this article we are going to upgrade our movement system by adding a click indicator and touch capabilities so it can be played on mobile devices. The indicator will show the player's destination an area is right clicked and disappear when the player arrives at that location.

Let's Begin

We are going to start by adding two new variables for our indicator. The top and the bottom portions.

// The movement destination indicator.
var indicatorTop;
var indicatorBottom;

Now we need to build our drawIndicator(). This function is going to draw our neat little indicator. I like the idea of a circle on the groud with a pyramid pointing down. If you don't like this look stretch your design muscle and make something even more aesthetic. Let's use the following code:

 * Draw indicator for movement destination.
function drawIndicator() {
  // Store variables.
  var topSize = characterSize/8;
  var bottomRadius = characterSize/4;
  // Create the top indicator.
  var geometry = new THREE.TetrahedronGeometry( topSize, 0 );
  var material = new THREE.MeshToonMaterial({ color: 0x00ccff, emissive: 0x00ccff  });
  indicatorTop = new THREE.Mesh( geometry, material );
  indicatorTop.position.y = 100; // Flat surface so hardcode Y position for now.
  indicatorTop.position.x = movements[ 0 ].x; // Get the X destination.
  indicatorTop.position.z = movements[ 0 ].z; // Get the Z destination.
  indicatorTop.rotation.x = -0.97;
  indicatorTop.rotation.y = Math.PI/4; = 'indicator_top'
  scene.add( indicatorTop );
  // Create the top indicator outline.
  var geometry = new THREE.TetrahedronGeometry( topSize + outlineSize, 0 );
  var material = new THREE.MeshBasicMaterial({ color : 0x0000000, side: THREE.BackSide });
  var outlineTop = new THREE.Mesh( geometry, material );
  indicatorTop.add( outlineTop );
  // Create the bottom indicator.
  var geometry = new THREE.TorusGeometry( bottomRadius, ( bottomRadius * 0.25), 2, 12 );
  geometry.dynamic = true;
  var material = new THREE.MeshToonMaterial({ color: 0x00ccff, emissive: 0x00ccff });
  indicatorBottom = new THREE.Mesh( geometry, material );
  indicatorBottom.position.y = 3;
  indicatorBottom.position.x = movements[ 0 ].x;
  indicatorBottom.position.z = movements[ 0 ].z;
  indicatorBottom.rotation.x = -Math.PI/2;
  scene.add( indicatorBottom );
  // Create the bottom outline.
  var geometry = new THREE.TorusGeometry( bottomRadius + outlineSize/10, bottomRadius / 2.5, 2, 24 );
  var material = new THREE.MeshBasicMaterial({ color : 0x0000000, side: THREE.BackSide });
  var outlineBottom = new THREE.Mesh( geometry, material );
  outlineBottom.position.z = -2;
  indicatorBottom.add( outlineBottom );

Now we need to remove the indicator when the character stops. We can just add the following code to the stopMovement() function.

  scene.remove( indicatorTop );
  scene.remove( indicatorBottom );

Now we want to show the indicator only when the character is moving and remove it when the character stops. To do this we check if the movement array isn't empty. This should be put in the render function. We will call our new function drawIndicator() so we can upgrade the movement condition in our render function to the following:

  // If any movement was added, run it!
  if ( movements.length > 0 ) {
    // Set an indicator point to destination.
    if ( scene.getObjectByName('indicator_top') === undefined ) {
    } else {
      if ( indicatorTop.position.y > 10 ) {
        indicatorTop.position.y -= 15;
      } else {
        indicatorTop.position.y = 100;
    move( rotationPoint, movements[ 0 ] );

Alright! We are done with the indicator. Now when you right click on the screen the indicator will appear and will disappear once your character has reached their destination. The last thing we want to do is add touchscreen capabilities so that we can navigate smoothly on mobile devices. First, we are going to add a variable to keep track of times between touch clicks. Add the following to the top of your file with the other global variables.

// Watch for double clicks.
var clickTimer = null;

Now we will build a function to detect a double click event.

 * Helper function to detect if the user quickly tapped twice.
function detectDoubleTouch() {
  // If a single click was detected, start the timer.
  if (clickTimer == null) {
    clickTimer = setTimeout(function () {
      clickTimer = null;
    }, 300);
  } else {
    // A double tap was detected!
    clickTimer = null;
    return true;
  // No double tap.
  return false;

This will set a timer when the first click is cast. If another click is detected within 300 milliseconds it will declare that a double tap and return true. This will be returned in the event hanlder that we will create next. Put the following code in your init() function.

document.addEventListener( 'touchstart', onDocumentTouchStart, false );

Now we are going to create the onDocumentTouchStart() function. In this function we are going to detect a double click since a single click, with a drag, will turn the screen.

 * Event that fires upon touch.
function onDocumentTouchStart( event ) {
  event.clientX = event.touches[0].clientX;
  event.clientY = event.touches[0].clientY;
  // Default touch doesn't offer a bypass.
  var bypass = false;
  // Detect if there was a double click. If so, bypass mouse button check.
  bypass = detectDoubleTouch();
  onDocumentMouseDown( event, bypass );

And that is it! We now have an indicator that will easily let the user see their destination. We also added touch screen capabilities for movement. Try out a working demostration below.

See the Pen Basic Threejs Game Tutorial Part 4: Moving 2 by Bryan Jones (@bartuc) on CodePen.

Add new comment

Restricted HTML

  • Allowed HTML tags: <a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <h5 id> <h6 id>
  • Lines and paragraphs break automatically.
  • Web page addresses and email addresses turn into links automatically.