Body animation isn’t smooth

The problem is that you wait for each keydown event to update the ship position.
The keydown event has a delay before it triggers again : the delay you are experiencing at beginning and the jump you face at each redraw.

The solution here is to trigger the movement on keydown and release it on keyup. This way, your ship will move smoothly as soon as you push the button.

// Im' assuming most of visitors here have recent browsers, so I removed the rAF polyfill for readibility

// If you wrap it after the canvas element decalaration, you can already populate this variable, it will avoid that you make a lot of calls to document.getElementById()
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
// ship data
var shipPositionX = canvas.width / 2;
// Just for the snippet height
var shipPositionY = 0;
var deltaShipPositionX = 10;
var deltaShipPositionY = 10;

//Removed the init() function, since our elements are loaded.


function draw() {
  clear();
  createRectangleToCoverCanvas();
  createSpaceShip(shipPositionX, shipPositionY, 10);
}

function clear() {
  ctx.clearRect(0, 0, canvas.width, canvas.height);
}

function createRectangleToCoverCanvas() {
  ctx.fillStyle="black";
  ctx.strokeStyle="black";
  ctx.beginPath();
  ctx.rect(0, 0, canvas.width, canvas.height);
  ctx.fill();
  ctx.stroke();
}

function createSpaceShip(x, y, radius) {
  ctx.fillStyle="white"
  ctx.strokeStyle="white"
  ctx.beginPath();
  ctx.rect(x, y, 20, 20);
  ctx.fill();
  ctx.stroke();
}
// instantiate a variable that will store our animationFrame id, so we can cancel it further
var raf, 
// the direction object, with an x and y values
    direction = {
      x: 0,
      y: 0
    };
// we can set a speed variable
var speed = 2.5;
function triggerMoveSpaceShip(event) {
  switch (event.keyCode) {
    // left
    case 37:
      // update the direction object
      direction.x = -speed;
      // avoid the scroll in the snippet
      event.preventDefault();
      break;

      // up
    case 38:
      direction.y = -speed;
      event.preventDefault();
      break;

      // right
    case 39:
      direction.x = speed;
      event.preventDefault();
      break;

      //down
    case 40:
      direction.y = speed;
      event.preventDefault();
      break;
  }
  // if we haven't initiated the animation yet, and that our direction is not 0, then do it now
  if (!raf && (direction.x || direction.y)) moveSpaceShip();
}

function releaseMoveSpaceShip(event) {;
  switch (event.keyCode) {
    // left
    case 37:
      //reset this direction
      direction.x = 0;
      break;

      // up
    case 38:
      direction.y = 0;
      break;

      // right
    case 39:
      direction.x = 0;
      break;

      //down
    case 40:
      direction.y = 0;
      break;
  }
  if (!direction.x && !direction.y) {
    // if none of the directions is set, stop the animation
    cancelAnimationFrame(raf);
    raf = undefined;
  }
}

function moveSpaceShip() {
  // declare our animation function
  var move = function() {
    // update the positions without going out of the screen
    // Sorry, this is dirty...
    if(direction.x){
    	if(
	    	(shipPositionX > 0 && shipPositionX < canvas.width-20) ||
			(shipPositionX <= 0 && direction.x > 0) ||
			(shipPositionX >= canvas.width-20 && direction.x < 0))
				shipPositionX += direction.x;
		}
	if(direction.y){
    	if(
	    	(shipPositionY > 0 && shipPositionY < canvas.height-20) ||
			(shipPositionY <= 0 && direction.y > 0) ||
			(shipPositionY >= canvas.width-20 && direction.y < 0))
				shipPositionY += direction.y;
		}

    // finally draw ou ship
    draw();
    // update our raf id
    raf = requestAnimationFrame(move);
  };
  // let's go !
  raf = requestAnimationFrame(move);
}


draw();

window.addEventListener('keydown', triggerMoveSpaceShip, true);
window.addEventListener('keyup', releaseMoveSpaceShip, true);
canvas {
  margin: auto;
  position: absolute;
  left: 0;
  top: 0;
  right: 0;
  bottom: 0;
  border: 1px solid black;
}
body{
   overflow: none;
  }
<canvas id="canvas" width="400" height="200"></canvas>

uncommented fiddle

Leave a Comment