Finished up the last of Sam Lacanshires basic HTML5 game tutorials and I moved on to the more advance tutorial that explains how to loop a sprite animation. I tried to combine the animation tutorial with the game tutorials I already had working but that went poorly and for some reason I could'nt even get the canvas to display.

As I am understanding more of how a game loop works (and just javascript in gernal really) we decided to scrap Nomad Axe as it was and make it more static. Maybe 'refactor' is a better term here. A motivator for this was a talk that came out of JSLA about setting up a javascript foundation for creating your own game and these slides from a developer in Australia. The slides walk through availble modules on npm which will help make Nomad Axe. The modularity provided by using browserify to load npm dependencies makes it easy to couple modules with small scope (instead of using complex frameworks with lots of missing peices) and save us some work so that we don't have to write everything from scratch.

In the tutorials I went through last week there is a run loop and an update loop that basically check to see if the game or the canvas has any changes. If there are then the canvas updates the changes and renders what you see. Evntually by following the tutorial you end up with a bunch of code like this:

var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');

canvas.width = 800;
canvas.height = 600;

var pacmanTiles = {
  loaded: false,
  image: new Image(),
  tileWidth: 64,
  tileHeight: 64
};

pacmanTiles.image.onload = function() {
   pacmanTiles.loaded = true;
}

pacmanTiles.image.src = 'pacman.png';

var mySprite = {
  x: 200,
  y: 200,
  width: 64,
  height: 64,
  speed: 200,
  state: 0
};

var itemCounter = 0;

var item = {
  x: Math.random() * canvas.width,
  y: Math.random() * canvas.height,
  width: 10,
  height: 10,
  color: '#fff'
};

var keysDown = {};
window.addEventListener('keydown', function(e) {
  keysDown[e.keyCode] = true;
});
window.addEventListener('keyup', function(e) {
  delete keysDown[e.keyCode];
});

function update(mod) {
  if (37 in keysDown) {
    mySprite.state = 2; //left
    mySprite.x -= mySprite.speed * mod;
  }
  if (38 in keysDown) {
    mySprite.state = 3; //up
    mySprite.y -= mySprite.speed * mod;
  }
  if (39 in keysDown) {
    mySprite.state = 0; //right
    mySprite.x += mySprite.speed * mod;
  }
  if (40 in keysDown) {
    mySprite.state = 1; //down
    mySprite.y += mySprite.speed * mod;
  }

  if (
    mySprite.x < item.x + item.width &&
    mySprite.x + mySprite.width > item.x &&
    mySprite.y < item.y + item.height &&
    mySprite.y + mySprite.height > item.y
  ) {
    item.x = Math.random() * canvas.width;
    item.y = Math.random() * canvas.height;
    itemCounter ++;
  }
}

function render() {
  ctx.fillStyle = '#000';
  ctx.fillRect(0, 0, canvas.width, canvas.height);

  if (pacmanTiles.loaded) {
    ctx.drawImage(
      pacmanTiles.image,
      mySprite.state * pacmanTiles.tileWidth,
      0,
      mySprite.width,
      mySprite.height,
      mySprite.x,
      mySprite.y,
      mySprite.width,
      mySprite.height
    );
  }

  ctx.fillStyle = item.color;
  ctx.fillRect(item.x, item.y, item.width, item.height);

  ctx.font = '12pt Arial';
  ctx.fillStyle = '#fff';
  ctx.textBaseline = 'top';
  ctx.fillText(itemCounter, 10, 10);
}

function run() {
  update((Date.now() - time) / 1000);
  render();
  time = Date.now();
}

var time = Date.now();
setInterval(run, 10);

Originally Nomad Axe would have been like this or would have used a complex engine to do the same thing which ultimately could have proved to be really clunky or hard to fix if something wasn't working quote right. For starters it was already a bit difficult to get IIO hooked and that's what lead to this refactoring in the first place. Now using the methodology I mentioned above, Nomad Axe is starting out looking like this:

var domready = require('domready')
var loaded = require('image-loaded')

domready(function(){
  console.log('dom loaded')

  var canvas = document.querySelector('canvas')
  var ctx = canvas.getContext('2d')
  console.log(ctx)

  canvas.height = document.height
  canvas.width = document.width

  var image = document.createElement('img')
  image.src = '/images/hero.png'

  loaded(image, function(err){
    if (err) console.error(err)
    ctx.drawImage(image, document.width/2, document.height /2)
  })
})

Now it's a little unfair to compare the two line by line because the tutorial code is actually checking for key presses and doing some other things I haven't hooked up in the new version of Nomad Axe yet. However there is a lot more code in the tutorial that straightens out some other things to get everything to work. The code from Nomad Axe is currently only displaying an image. It can't move or anything, however the variable loaded is being assigned by requiring a Node.js module called image-loaded. All it does is check to see if an image is loaded or not. When the game is actually running there will be a lot of images to check for. Now instead of writing all of those checks out by hand I can use the simple function 'loaded' to save a bunch of work.