Learn Canvas and JavaScript Animation by Creating a Vertical Shooter (SMOOTH MOVEMENT) – Part 9

Stage 9: Smooth Player Movement

So far our player’s plane follows the mouse exactly. This makes for a fairly easy game; a much more difficult method would be for the plane to move slowly and smoothly toward the mouse but to do this we need to use some of our grade 7 mathematics.

Grade 7 Mathematics

Remember that to calculate the distance between two points we can use Pythagoras’ theorem (). We will use this to calculate the distance from our plane and the mouse and then divide it by how many fractions of a second we want our plane to take to reach the current mouse location, remembering that our plane’s location will be updated every 10 milliseconds. We will also need to calculate some angles and distances using our trig rules, SOH, CAH, TOA (…okay sorry, these rules weren’t from grade 7). With this information we will calculate the direction and distance to move our plane each run loop. In mathematics, we call a measurement that has both direction and magnitude a vector.

Let’s image that we have a scenario like the diagram below where we have the mouse pointer on the top-right with coordinates (Xm,Ym) and the plane (triangle) on the bottom-left with coordinates (Xp,Yp). We don’t want our plane to jump straight to (Xm,Ym) , instead we want it to only move a certain distance towards those coordinates, this is the vector that we want to calculate.

From the diagram above you can see that we have a few right-angle triangles and you might remember some of the trig rules that we can use to work out distances and angles. The most obvious thing we need to calculate is the x and y distance that our plane will move each run loop. This will need to be a two-step process because while we can assign a distance to move (hypotenuse) we don’t know either x? or y? so we will need to calculate the angle Θ.

So let’s imagine we want to move 5 pixels each run loop, we would use the Tan rule with the opp and adj being the y difference and x difference between our plane and mouse location. The formula for tangent is   but we want to find the angle Θ so rearranging we can calculate the angle of our vector using . The JavaScript function to calculate inverse tan is Math.atan() but this does not calculate the angle for all quadrants[1], just the first so we will use Math.atan2(xlength,ylength). Have a look over the new code below for a description of what each line does. Add this code into our playerPlane() function:

function playerPlane(file, x, y, width, height) {
  this.health = 3;
  this.score = 0;
  this.playerFlash = false;
  …
  …
  …
  this.xcenter = 0;
  this.ycenter = 0;

  this.update = function () {
    this.xcenter = this.x + this.width / 2;
    this.ycenter = this.y + this.height / 2;
    this.calculateMoveVector();

    if (!this.playerFlash) {
      ctx.drawImage(this.image, this.x, this.y, this.width, this.height);
    }
    …
  };

  this.flashPlayer = function () {
    player.playerInvulnerable = true;
    player.playerFlash = true;
    …
  };
  this.calculateMoveVector = function () {
    var xlength = (this.xcenter - this.xm);
    var ylength = (this.ycenter - this.ym);
    var distance= Math.sqrt(xlength*xlength+ylength*ylength)/30;
    var angle = Math.atan2(ylength, xlength);
    this.xdistance = distance * Math.cos(angle);
    this.ydistance = distance * Math.sin(angle);
    this.x = this.x - this.xdistance;
    this.y = this.y - this.ydistance;
  };
}

The line var distance= Math.sqrt(xlength*xlength+ylength*ylength)/30; calculates the distance from the mouse and plane using Pythagoras. The “/30” reduces the distance by 30 times. Therefore it will take 30 run loop cycles to reach the mouse. How many seconds is that if our run loop happens every 16.7 milliseconds?

Change this /30 to something different if you want the plane to move faster or slower.

Finally, we need to replace our old mousemove code to include this new smooth movement calculation. Rather than move the player instantly to a new location they store the mouse location in two variables xm,ym. They are used by the calculateMoveVector function. 

Replace the old lines:

player.y = mousePos.y – player.height / 2;

player.x = mousePos.x – player.width / 2;

With the lines shown here:

window.onload = function () {
  gameCanvas = document.getElementById("gameCanvas");
  gameCanvas.width = canvasWidth;
  gameCanvas.height = canvasHeight;
  ctx = gameCanvas.getContext("2d");
  …
  player = new playerPlane("myplane.gif", canvasWidth / 2, canvasHeight / 2, 100, 100);

  gameCanvas.addEventListener('mousemove', function(event){
    var mousePos = getMousePos(gameCanvas, event);
    player.xm = mousePos.x;
    player.ym = mousePos.y;
  }, false);

  for (var i = 0; i < maxBullets; i++) {
    bulletArray[i] = new bullet();
  }
  …

  soundtrack = new gameAudio("01_Main Theme.mp3", true, false);
  explosionSound = new gameAudio("snd_explosion2.wav", false, true);
  bulletExplosionSound = new gameAudio("snd_explosion1.wav", false, true);
};

Play your game, it should now move smoothly toward your mouse. If you don’t like this you could always get rid of the “/30” from the var distance calculation for instant move again (or undo all our code changes).

Move on to stage 10 –>
Jump to: [Vertical Shooter Post: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 ]


[1] Have a quick look over your old mathematics textbooks to see what quadrants Tan will be positive, I learnt “All Stations To Central”. For a video describing the situation have a look at Khan Academy (Unit Circle), around 6 minutes 38 and following.