Monday, 19 December 2011

More matrices

Last week I wrote about one way to use matrices, passing values to the Matrix constructor to make a transform or scale matrix. Matrices made this way can be passed to functions that need them, minimising the number of lines and temporary variables. This approach is fine for simple uses but breaks down for more complex applications, as the values passed to the constructor require multiple calculation steps, too much to do inline. Fortunately there is another, easier, way.

The Matrix class has methods for all of the transformations needed in two dimensions, using only the values needed for that transformation, so there's no need to set the Matrix properties directly. Using these calls the examples from last week look like this:

function DrawWall(iX:int, iY:int):void {
 var fX:Number = Game.kiTowerSize * iX;
 var fY:Number = Game.kiTowerSize * iY;
 var mat:Matrix = new Matrix();
 mat.translate(fX, fY);
 baseBmp.draw(dataWall, mat);

fScale = bitmapData.width / tmpBase.width;
var mat:Matrix = new Matrix();
mat.scale(fScale, fScale);
bitmapData.draw(tmpBase, mat, null, null, null, true);

In each case a temporary Matrix is created then modified with a method call. This is easier than remembering all the properties that need to be set, although it takes more lines of code and requires an extra variable.

It really comes into its own when combining transformations, when an object is to be transformed twice or more in sequence. If the transformation methods are called in order they are applied one after the other to the Matrix, as if multiple matrices were being concatenated (multiplied) without the need to call the concat() function. 

For example the following code reflects (using the scale function) and translates a BitmatData into itself, as if it were reflected in a line fW pixels from the left edge (the half-way line of the BitmapData which is twice as wide).

var mat:Matrix = new Matrix();
mat.scale(-1, 1);
mat.translate(fW, 0);
datLens.draw(datLens, mat);

The next code does rather more: it translates to adjust the registration point of a BitmapData being drawn. It then randomly rotates it and scales it, before placing it where it is needed. It draws the 'splat' when bugs die in Bug Tunnel Defense.

var mScale:Matrix = new Matrix();
mScale.translate(-fHalfSize, -fHalfSize);
mScale.rotate(Math.random() * 2 * Math.PI);
mScale.scale(fScale, fScale);
mScale.translate(fX, fY);
baseBmp.draw(data, mScale, ctSplash);

The order of the calls is important: almost all of them have to be in this order. One way to think of it is the calls go from the inside to the outside. First adjust the registration point which is internal to the object. Then rotation and scale about this point (rotation and scale can be done in any order). Finally translate it relative to other objects, in this case in a bitmap which acts as the ground. 

No comments:

Post a Comment