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.

Leave a Reply

Your email address will not be published. Required fields are marked *