tags:

views:

443

answers:

1

This is a test program to measure the time it takes Flash to draw a triangle 10,000 times.

The app (code below) calls runTimeTest() every N seconds which draws the triangle 10,000 times.

Now for the "interesting" part: each call takes increasingly more processor until after about the 6th or 7th call it goes to "infinity" (see screen shot of TaskManager)

Weird bug or explainable??

// create a Canvas to draw on

var c:Canvas = new Canvas();

function onApplicationComplete(e:Event)
{
 c.width = width;
 c.height = height;

 c.x = 0;
 c.y = 0;

 addChild(c);

 // set up a timer to run every 10 seconds

 var timer:Timer = new Timer(10000);
 timer.addEventListener(TimerEvent.TIMER, runTimeTest);
 timer.start();
}

function runTimeTest(e:Event)
{
 // this is called every 10 seconds

 var x0:int, x1:int, x2:int;
 var y0:int, y1:int, y2:int;

 // set triangle vertices

 x0 = 100; y0 = 500;
 x1 = 120; y1 = 515;
 x2 = 155; y2 = 500;

 // draw a filled triangle 10,000 times

 for (var i:int = 0; i < 10000; ++i)
 {
  c.graphics.beginFill( 0xff0000, 1 );
  c.graphics.moveTo( x0, y0 );

  c.graphics.lineTo( x1, y1 );
  c.graphics.lineTo( x2, y2 );
  c.graphics.lineTo( x0, y0 );

  c.graphics.endFill();
 }
}

i34.tinypic.com/jutpwo.png

+2  A: 

"How about if you call c.graphics.clear() at the beginning of runTimeTest?"
James Ward

Yes, adding c.graphics.clear() fixed it.
Matt

Flash persists all drawing commands (i.e. graphics) until you call graphics.clear(). This so that you can draw over multiple frames without having to draw everything at once.

The reason it takes longer and longer to draw the triangles is that each time you call runTimeTest() Flash is having to draw an extra 10,000 triangles.

So the first time it is called Flash draws 10,000 triangles, the second time you call runTimeTest() it has to draw the first 10,000 triangles (because you haven't cleared the canvas) and then the second 10,000 triangles.

The solution, as Glenn points out, is to clear the canvas prior to drawing each set of triangles. That way Flash only has to draw the current set of triangles.

If, for whatever reason, you do need to draw an absurd number of items to the screen you can take advantage of bitmap caching: if you draw graphics on a different Canvas/Sprite each time then Flash only has to draw each graphic once (the others are cached in memory behind the scenes).

e.g.

private function drawTriangles():void
{
 var x0:int, x1:int, x2:int;
 var y0:int, y1:int, y2:int;

 // set triangle vertices

 x0 = 100; y0 = 500;
 x1 = 120; y1 = 515;
 x2 = 155; y2 = 500;

 // This is the important part.
 // Draw 10,000 triangles only on this new sprite.
 var c:Sprite = new Sprite();
 c.cacheAsBitmap = true;
 addChild(c);


 for (var i:int = 0; i < 10000; ++i)
 {
  c.graphics.beginFill( 0xff0000, 1 );
  c.graphics.moveTo( x0, y0 );

  c.graphics.lineTo( x1, y1 );
  c.graphics.lineTo( x2, y2 );
  c.graphics.lineTo( x0, y0 );

  c.graphics.endFill();
 }

}

With this method you will notice that it takes approximately the same amount of time to draw the triangles every time (because, Flash is really only drawing the same number of things each time).

Just note that you gain the greatest benefits to bitmap caching when you are dealing with largely static graphics.

In general, only draw what you need and do a graphics.clear() if you don't need to keep what was previously on the canvas.


In response to Matt's comment:

Do you mean if endFill() was not called after each triangle (as it currently is)?

That wouldn't have any performance benefits, it would just change what was drawn. If you draw over the same area during the same beginFill/endFill section it will "invert" the drawn section each time.

It's a little hard to explain without an example...

Lets alter your triangle function so that it will draw two triangles in the same beginFill/endFill section:

 c.graphics.beginFill( 0xff0000, 1 );
 for (var i:int = 0; i < 2; ++i)
 {
  c.graphics.moveTo( x0, y0 );

  c.graphics.lineTo( x1, y1 );
  c.graphics.lineTo( x2, y2 );
  c.graphics.lineTo( x0, y0 ); 
 }
 c.graphics.endFill();

If you run that then you won't see anything on the screen!

That's because you are drawing over the same area twice and it's being inverted (made transparent) - Flash is technically still drawing it, but you just can't see it.

If you change the number of iterations to 3 then you'll see the triangle again (because it toggles each time from visible -> invisible -> visible).

This page explains it quite nicely (see the 'Winding' section about a third of the way down) - although it's talking specifically about Flash Player 10, the same idea applies in previous versions, we just didn't have control over it back then :) http://www.flashperfection.com/tutorials/Flash-Player-10-Drawing-API-10877.html

Sly_cardinal
Thanks, Sly, for the information. I was not aware that Flash persists all the draw commands until a clear(). I wonder what would happen if endFill() were called after each triangle? I may test that. Thanks again, Matt
Matt