Graphics Programming Environment Shootout Episode 2: ActionScript

This article is the second in a series in which I implement the same app in several different graphical programming environments. Coming up this round: ActionScript.

ActionScript is the scripting language that comes with Flash. As such, it’s attached to one of the most popular environments for high-performance 2D graphics rendering in existence. Flash is much more feature-rich than Processing, and I was expecting that its general purpose nature would cost it in terms of performance. I was wrong.

“imagine” in ActionScript

You can view the implementation of “imagine” in ActionScript, or check out the source code.

Performance: On my Intel Core i7 MacBook, this app runs at 13.3 frames per second with 8000 sparks on screen – about 25% faster than the Processing version. Of course this doesn’t mean that Flash is generally faster than Processing, only that Flash is faster at drawing circles on an Intel Mac. However the result is surprising to me, because of the nature of Flash.

The Flash environment

Whereas Processing provides a raster canvas for your code to draw on, Flash provides a scene graph. This means that you add objects to the stage, and these objects can contain child objects, which themselves have children, forming a tree structure. Moving or rotating an object will also move and rotate its children. In processing when you draw one object on top of another one, the original object is gone forever. In Flash when you add one object on top of another, the new object can be removed to reveal the original object again. Scene graphs are intrinsically more memory and processor intensive than raster canvases.

Flash’s scene graph is extremely useful for animating, because it reflects the way that objects in the real world are made up of component parts. Say you want to animate a moving car with spinning wheels. The wheels must be separate objects to the car, because you want them to rotate independently of the car. But when you move the car you expect the wheels to move with the car. Scene graphs make it easier to construct realistic and nuanced interactive animations like this one:

However, this ability comes at a cost. In a flash app, you can’t draw pixels directly to the display, you must set up an object in the scene graph to handle bitmap drawing. In the last episode I gave a 20 line code sample for making a very simple Processing app. The equivalent in ActionScript is twice as long:

package
{
  import flash.display.*;
  import flash.events.*;
  import flash.geom.*;
 
  [SWF(width="400", height="400")]
 
  public class Main extends Sprite  
  {
    private const bg:uint = 0xFFFF0088;
 
    private var buffer:BitmapData;
    private var canvas:Shape;
 
    public function Main()
    {
      canvas = new Shape();
      buffer = new BitmapData(stage.stageWidth,
                      stage.stageHeight, false, bg);
      addChild(new Bitmap(buffer));
      stage.addEventListener(Event.ENTER_FRAME, draw);
      stage.addEventListener(MouseEvent.CLICK, reset);
    }
 
    private function draw(e:Event):void {
      canvas.graphics.clear();
      canvas.graphics.lineStyle(1, 0);
      canvas.graphics.beginFill(0xFFFFFF);
      canvas.graphics.drawCircle(random(-100, 500),
                      random(-100, 500), random(10, 100));
      buffer.draw(canvas);
    }
 
    private function reset(e:Event):void {
      buffer.fillRect(new Rectangle(0, 0, stage.stageWidth,
                      stage.stageHeight), bg);
    }
 
    private function random(from:Number, to:Number):Number {
      return from + Math.random() * (to - from);
    }
  }
}

Not only is this source code long, but it has some gotchas that didn’t exist in the processing version. The “stage.” in “stage.addEventListener(MouseEvent.CLICK, reset);” on line 23 is an unusual pattern that is required in this case because Bitmap objects (unlike most other display objects) don’t respond to MouseEvents. If you omit the step of clearing the graphics canvas at the start of draw() then the animation will appear to work as normal, but will slow down over time as the canvas fills up with vector data that takes longer and longer to render. Good luck figuring those things out if you’re on your first ActionScript project.

This is the price of flexibility. Flash’s object-oriented scene graph approach makes it suitable for building complex interactive programs like inamo and UI frameworks like Flex, but for the kind of light graphical experiment that Processing excels at, ActionScript feels clunky.

The good news is that apparently performance doesn’t suffer as a result. Even with the overhead of interpreting the scene graph, the Flash port of imagine is faster than the Processing version, presumably because Flash’s rendering engine is more heavily optimised than the Java2D implementation on a mac.

Conclusion

Flash is a very flexible graphical environment, but getting it to do exactly what you want takes some expertise.

Next up: JavaScript & Canvas