Notes on Flash and ActionScript 3 Development

Notes on Flash and ActionScript 3 Development

Lately I've been doing a lot of development in Flash. Flash being a platform that neither I nor Apple have cared very much for in the past, it has been quite an interesting experience. I played with Flash 3 way back when the world was young, and I'm positively surprised by the full-fledged development environment Flash has morphed into.

My development is basically all ActionScript 3. I use the free and fantastic FlashDevelop[a] IDE. My viewpoint therefore is strictly the viewpoint of a Flash programmer as opposed to a Flash artist.

If there is another development platform that is similar to Flash, I'd have to say that Java is the closest one. Both are managed OO languages with a large API - the fact that Java is very much a server-side language and Flash very much a client side one shouldn't be allowed to obscure the similarities. C++ with Boost is somewhat like it, but isn't managed. AS3 syntax is reminiscent of Pascal / Delphi, but the similarity is only skin deep.

All platforms have warts, and Flash is no exception. Here the warts are basically all leftovers from the time when Flash was a format for delivering vector animations, with ActionScript as a bolted-on afterthought. A lot of the API is therefore cluttered with parts that are just plain odd. For example, the flash.geom.Matrix3D class.

Creates a Matrix3D object. Matrix3D objects can be initialized with a Vector of 16 Numbers, where every four elements can be a row or a column.

ActionScript 3 Reference[b]

Here we go: every four elements can be a row or a column, yes, but which one is it - is it row- or column-major form? The reference doesn't say. Experimenting a little I can reveal that the numbers are given in column-major form. That is:

var val:Vector.<Number> = new Vector.<Number> ();
val.push (1, 2, 3, 4, 5, 6, 7, 8, 
    9, 10, 11, 12, 13, 14, 15, 16);

var M:Matrix3D = new Matrix3D (val);

//     [ 1   5   9  13]
// M = [ 2   6  10  14]
//     [ 3   7  11  15]
//     [ 4   8  12  16]

The second issue is that a Matrix3D doesn't really behave like a matrix.

var val:Vector.<Number> = new Vector.<Number> ();
val.push (1, 2, 3, 4, 1, 2, 3, 4, 
    1, 2, 3, 4, 1, 2, 3, 4);

var M:Matrix3D = new Matrix3D (val);

//     [ 1   1   1   1]
// M = [ 2   2   2   2]
//     [ 3   3   3   3]
//     [ 4   4   4   4]

var x:Vector3D = new Vector3D (1, 0, 0, 0);

var y:Vector3D = M.transformVector (x);

At this point we would expect y to equal (1, 2, 3, 4) - the correct result of multiplying M on the right with x. It doesn't. y equals (2, 4, 6, 8), which caused me much confusion until I understood that transformVector doesn't really do a matrix-vector multiplication. What happens is that the vector is multiplied with the sub-matrix consisting of the first three columns. Then the first three elements of the fourth column is added to the result. This is pretty much how I would write a linear transform if I knew that client code wouldn't know how to use homogenous coordinates. It is, however, a royal pain when something advertised as being a matrix, isn't.

This is only one example. I could go on about...

  • Vector3D.subtract has some errors in the documentation. The method description reverses the order of the operands, implying that a.subtract(b) results in b - a.

    Subtracts the value of the x, y, and z elements of the current Vector3D object from the values of the x, y, and z elements of another Vector3D object.

    ActionScript 3 Reference[c]

    The parameter description is the right one - a.subtract(b) results in a - b, just as you would expect.

        a:Vector3D - The Vector3D object to be subtracted from the current Vector3D object.

    ActionScript 3 Reference[d]

  • ...the whole documentation of Vector3D which reads like a description of vectors written by someone who doesn't really know what they're writing about.

  • ...the hoops you need to jump through to get double click events to fire.

  • alpha blending is handled (poorly).

Despite all this, AS3 is a very capable language. It clearly shows its roots and seems to be aimed at simpler graphics tasks. I do think that a once-over audit of the documentation would be desirable - just to make sure that everything is properly described - and that things should be named appropriately. APIs should follow the principle of least astonishment[e]: AS3 doesn't quite do that. My first suggestion would be to have a look at another high-performance graphics API, like OpenGL. It is not perfect, but it captures a lot of the principles of how high-performance graphics are done. As it is now, a lot of the things in the API feel rushed - like they were written by someone who wasn't really an expert in the domain. Unfortunately we're stuck with the rushed results, and perhaps they are preferable to the very-late-or-no-results of the HTML 5 process.