Useful JavaScript Game Extensions: Array#shuffle

Do the shuffle! Array#shuffle

Part 7/256

Shuffling is important, especially in card games.

/**
 * Returns a new array with the elements all shuffled up.
 *
 * @returns A new array that is randomly shuffled.
 * @type Array
 */
Array.prototype.shuffle = function() {
  var shuffledArray = [];
 
  this.each(function(element) {
    shuffledArray.splice(rand(shuffledArray.length + 1), 0, element);
  });
 
  return shuffledArray;
};

Notice how building on the previous components of rand and each makes this method much easier to write. You’ll find that when you surround yourself with great APIs things constantly become easier and easier, whereas when you are surrounded with terrible APIs things become harder and harder.

Useful JavaScript Extensions: Number#times

Part 5/256

For loops… I hate them so much. Fortunately, a well established functional iteration convention is the Number#times method.

/**
 * Calls iterator the specified number of times, passing in a number of the 
 * current iteration as a parameter. The number will be 0 on first call, 1 on 
 * second call, etc. 
 * 
 * @param {Function} iterator The iterator takes a single parameter, the number 
 * of the current iteration.
 * @param {Object} [context] The optional context parameter specifies an object
 * to treat as <code>this</code> in the iterator block.
 * 
 * @returns The number of times the iterator was called.
 */
Number.prototype.times = function(iterator, context) {
  for(var i = 0; i < this; i++) {
    iterator.call(context, i);
  }
  return i;
}

This hides the inner workings of the iteration from the calling code so there’s no need to keep track of an external dummy iterator variable if you don’t want to.

var n = 3;
 
// Greets you three times, with respect
n.times(function() {
  alert("O HAI!");
});
 
// logs: 0, 1, 2
n.times(function(i) {
  console.log(i);
});

Useful JavaScript Game Extensions: Array#remove

Debris Removal
Part 4: Array#remove

JavaScript Arrays are missing some very common, very useful functions. One of those is the remove method. We want to be able to say “Hey you, array, remove this object from yourself! Now!!” But our poor JS array’s don’t know how. They can barely remove elements from specific indices, let alone a specified object. Well no longer! Now they’ll do what we say.

/**
 * Remove the first occurance of the given object from the array if it is
 * present.
 *
 * @param {Object} object The object to remove from the array if present.
 * @returns The removed object if present otherwise undefined.
 */
Array.prototype.remove = function(object) {
  var index = this.indexOf(object);
  if(index >= 0) {
    return this.splice(index, 1)[0];
  } else {
    return undefined;
  }
};

By building off of the Array‘s built in methods we can keep this code very short. We find the first occurrence of the specified object using indexOf, then we remove and return it using splice. If it wasn’t found we return undefined instead.

// An illustrative test suite
 
test("Array#remove", function() {
  ok([1,2,3].remove(2) === 2, "[1,2,3].remove(2) === 2");
  ok([1,3].remove(2) === undefined, "[1,3].remove(2) === undefined");
  ok([1,3].remove(3) === 3, "[1,3].remove(3) === 3");
 
  var array = [1,2,3];
  array.remove(2);
  ok(array.length === 2, "array = [1,2,3]; array.remove(2); array.length === 2");
  array.remove(3);
  ok(array.length === 1, "array = [1,3]; array.remove(3); array.length === 1");
});

John Resig has another take on Array#remove, remove by index. You may want to take a look at that as well, though for me it feels more natural to remove by specified object rather than by specified index.

Useful JavaScript Game Extensions: Array#rand

Ayn Rand

Part 3 of 256.

/**
 * Randomly select an element from the array. The array remains unmodified.
 *
 * @returns A random element from an array, or undefined if the array is empty.
 */
Array.prototype.rand = function() {
  return this[rand(this.length)];
};

Building on the last installment of a global rand method, we can easily extend Array to provide simple random element selection.

// Example:
["rock", "paper", "scissors"].rand()

Selecting options from a loot table, or random AI actions is now wonderfully easy. With all these extensions the theme is the same, start with the best interface for the programmer and extend what you must to make it happen.

Useful JavaScript Game Extensions: rand

Rand Atlas Shrugged
Part 2 of my 256 part series: Useful JavaScript Game Extensions!

/**
 * Generate uniformly distributed random numbers.
 *
 * @param {Number} [n]
 * @returns A Random integers from [0, n) if n is given, otherwise a random float
 * between 0 and 1.
 * @type Number
 */
function rand(n) {
  if(n !== undefined) {
    return Math.floor(Math.random() * n);
  } else {
    return Math.random();
  }
}

Some games make use of random numbers… a lot. So when choosing the best interface it is important to keep that in mind. Often times uniform distributions are the way to go, such as when selecting from an array, or rolling a six sided die. If one often has need of a variety of random distributions then having different methods live in a Random namespace would probably be best. For simple, everyday use a little rand(6) is very convenient.

Useful JavaScript Game Extensions: Clamp

Give him the clamps!

Part 1 of my new 256 part series on simple JavaScript extensions to make game programming easy and fun!

/**
 * Returns a number whose value is limited to the given range.
 *
 * Example: limit the output of this computation to between 0 and 255
 * (x * 255).clamp(0, 255)
 *
 * @param {Number} min The lower boundary of the output range
 * @param {Number} max The upper boundary of the output range
 * @returns A number in the range [min, max]
 * @type Number
 */
Number.prototype.clamp = function(min, max) {
  return Math.min(Math.max(this, min), max);
};

Note that this extends the behavior of the Number class. Some may consider it poor form to “mess with” the JS built-ins, but I consider it poor form to expose a worse than necessary interface to the programmer. Compare:

// Namespace?
STRd6.Util.clamp(x * 255, 0, 255);
 
// global function clamp?
clamp(x * 255, 0, 255);
 
// Clean, simple and object oriented!
(x * 255).clamp(0, 255);

Stay tuned for the next 255 parts of the series!

jQuery style events

jQuery events are cool. But what if you want to trigger some events but not extend all your JavaScript objects to jQuery ones? If you are drawing thousands and thousands of these objects to screen you probably don’t want to worry about the overhead of making them jQuery objects.

Here’s how you can write your own simple jQuery style events:

function Meteor() {
  var eventCallbacks = {
    'destroy': alert('destroyed')
  };
 
  var destroyed = false;
 
  var self = {
    bind: function(event, callback) {
      eventCallbacks[event] = callback;
    },
    destroy: function() {
      if (!destroyed) {
        destroyed = true;
        self.trigger('destroy');
      }
    },
    explode: function() {
      // Kaboom
    },
    trigger: function(event) {
      eventCallbacks[event](self);
    },        
  };
  return self;
}

Here’s how you use it

var meteor = Meteor();
meteor.bind('destroy', function() { 
  meteor.explode();
});
 
...
 
meteor.destroy();

matrix.js Demo

Excerpts, source code and images are great, but a working example is even greater. That’s why I’ve cobbled together a working demo just for you! View it here: Matrix Demo. I’ve extracted it to just the minimum that you need to work with. Jump Straight to the guided tour.

Some Background

Though matrix.js has no dependencies, I depend on jQuery to code in JavaScript without sobbing uncontrollably. This code makes use of jQuery, though you should be fine if you are familiar with any major JS framework.

There are two main components that need to be brought together to make a decent demonstration: object(s) with nested component(s) and a canvas that can understand matrices.

Canvas

The canvas implementation of matrix transformations is mega-clunky, but that won’t bother us any longer.

        var canvas = $('#gameCanvas').get(0).getContext('2d');
 
        $.extend(canvas, {
          withTransform: function(matrix, block) {
            this.save();
 
            this.transform(
              matrix.a,
              matrix.b,
              matrix.c,
              matrix.d,
              matrix.tx,
              matrix.ty
            );
 
            try {
              block();
            } finally {
              this.restore();
            }
          }
        });

The withTransform method takes a matrix and a function (code block). It handles saving the context, applying the elements in the matrix to the correct parameters, calling the code block, and restoring the saved context no matter what, even if the code block throws an exception up in its face after eating bad seafood. It will stop at nothing to make your programming dreams come true.

Rather than handle all that junk ourselves every time want to draw a rotated top hat, we can instead do something like:

        var matrix = Matrix.rotation(Math.PI/2);
        canvas.withTransform(matrix, function() {
          // I'm so carefree, I can draw and draw without worrying about
          // saving or restoring the context, or what order those 4 trig
          // dealies go in. Thank you matrix.js for saving my life and
          // becoming my new best friend. <3<3<3 XOXO !!!1
        });

Hand-crafted matrix elements do not have more value than those forged in the heart of a machine.

Objects

Ok, so the canvas can handle matrix transforms easily, big deal. I just want to put a top hat on a dinosaur, make him dance, and laugh on into the early morning light.

  var hat = GameObject("images/accessories/tophat.png", Matrix.translation(30, -32));
 
  var dino = GameObject("images/levels/dino1.png", Matrix.translation(320, 240), [
    hat
  ]);

Done!

I’ve called my objects GameObject because sometimes I make games. The constructor takes 3 arguments, a url for an image, the transformation matrix of the object, and a list of component objects to draw inside it. I’ve got a dinosaur and the dinosaur has a hat.

To actually draw the dino we have a classic game loop.

  setInterval(function() {
    canvas.fill('#A2EEFF');
 
    dino.draw(canvas);
  }, 33);

Only the dino needs to be drawn because he’ll take care of drawing his own hat.


Making him dance

This is the part where you open up the demo page, fire up your JS console, and play along.

We want to move the dino up a little bit. Remember, up is negative.

  dino.translate(0, -50);

Now we want to rotate him.

  dino.rotate(Math.PI / 3);

Now we want him to walk warily down the street with his brim pulled way down low.

  // Brim down
  hat.translate(0, 10);
 
  // Walk warily...?
  (function() {
    var i = 0;
    setInterval(function() {
      dino.rotate(Math.sin(i / 8) * (Math.PI / 6));
      i++;
    }, 33);
  }());

Well you get the idea. If things get too nuts just refresh and start again.

Images Extras (Bonus Section!)

Even assuming you already have an image and HTML5 Canvas all set up, it is still a giant pain to draw it on there. Not to mention loading an image or waiting for it to load. So step one is to remove the tedium from drawing images onto the canvas forever.

  var sprite = Sprite.load(imageUrl);
  sprite.draw(canvas);

Wow, that was easy! Take a look at the Sprite class in the source for more on this miraculous occurrence.