Learn to Optimise your AS3 Code for Speed and Performance

by Michael James Williams on February 10, 2010 · 34 comments

in Articles,AS3 Concepts Explained

Optimisation is about making your code more efficient. Usually you’ll optimise for speed — not to make the gameplay faster, necessarily, but to keep the game running smoothly, with no lag.

(If your SWF is a few MB larger than you’d like, you’d want to optimise for size, but that’s a different topic for a different post.)

The hundreds of tricks and techniques to do this boil down to one principle:

Don’t make Flash do more work than it needs to

For example, suppose you have a line like this:

var newX:Number = ( 47 * Math.sin( Math.PI * 23 / 109 ) / 121.88 ) + player.x;

…and you run that line every tick or every frame. Look at all the work you’re making Flash do!

It’s got to get the value of pi and multiply it by 23, then divide that by 109, then get the sine of that number, then multiply that by 47, then divide it all by 121.88, and finally add the player’s x-position.

If you grab your calculator, you can find that 47 * Math.sin( Math.PI * 23 / 109 ) / 121.88 is 0.237317256. That’s not going to change; we don’t need to make Flash keep calculating that over and over again. So that line can be rewritten:

var newX:Number = 0.237317256 + player.x;

Suddenly, Flash has much less work to do — you’ve done the work for it.

Let’s look at some better examples…

Creation is slow

Whenever you write someObject = new Whatever(), Flash has to do a whole bunch of stuff behind the scenes involving memory and references and goodness knows what else. This takes time. Learn from eco-protesters and recycle, instead.

For example, in my avoider game I create new enemies at the top of the stage, move them down every tick, and remove them when they reach the bottom.

screenshot

So, Flash has to deal with a call to new Enemy() every few ticks — slow!

Instead of removing the enemies that reach the bottom, I could move them back to the top, and reuse them:

screenshot

This requires more code (and more work on our part); rather than writing:

newEnemy = new Enemy( startX, startY );

…we’ll have to keep track of old enemies that have moved off the screen, then pick one when it’s needed and call:

oldEnemy.x = startX;
oldEnemy.y = startY;

It’s a trade-off; working out all the new code logic requires time and work on our side, but reduces the time and work required by Flash — though we only have to write the code once!

Drawing is slow

Any time there’s a change on the screen, remember: Flash has to redraw all those pixels. Sometimes, setting your game’s frame rate to 24fps can actually make it run more smoothly than at 30fps, because there’s a little extra time each frame to do all the drawing work.

Alpha is a source of lag. If you’ve got a semi-transparent object (object.alpha = 0.5) then Flash has to draw that object and the object behind it:

screenshot

Graphical filters require a lot of work on Flash’s part, too. Calculating (and then drawing) a glow, a shadow, or a blur is a heavy operation.

screenshot

Do you need to apply these effects on the fly? Often you can generate them in Photoshop beforehand.

When you’ve got a lot of objects on-screen at once, it can even be faster to bypass Flash’s built-in drawing routines altogether, and write your own. (I have a tutorial on “blitting” like this lined up for next week.)

Pixel-perfect collision detection is slow

Flash’s DisplayObject.hitTestObject() method is a simple way to detect whether the axis-aligned bounding boxes of two objects are overlapping:

screenshot

…but this isn’t always good enough:

screenshot

We can use a pixel-perfect collision method (such as this one), but these are very slow — you’re making Flash check every single pixel of one object against every single pixel of the other, to see if any overlap. If there are a lot of potential collisions, this can take a loooong time.

Since each method has its advantages (speed vs. accuracy), we can use a combination of the two: use hitTestObject() to see if any two objects are overlapping, and if they are, use a pixel-perfect method to see if they’re actually colliding. It’s slower that just using hitTestObject(), but much faster than using only the pixel-perfect method — and you get the accuracy of the latter.

Optimise your design, too

You know what’s faster than using the two-stage collision detection routine outlined above? Not needing to use pixel-perfect collision detection at all.

If all your objects fit snugly inside rectangles, you’ll be fine just using hitTestObject.

screenshot

Likewise, if you use simple line-art, you probably won’t need alpha transparencies or fancy graphical filters. If you only have eight objects on-screen at any one time, you don’t have to worry about creating new ones.

Sometimes it’s OK to let restrictions alter your design.

Avoid premature optimisation

Optimising code as you write it is a waste of time.

That first draft should be loose and easy to change; focus on getting it working and trying out new features before you worry about making it lightning fast.

If you try to make every line perfect as you write it, it’ll slow you down. Plus, you’ll be reluctant to change it later.

Also, don’t over-optimise. Consider this:

if ( player.x > playingField.rightEdge.x )
{
    player.x = playingField.rightEdge.x;
}

It would be faster to run:

if ( player.x > 150 )
{
    player.x = 150;
}

(…assuming that playingField.rightEdge.x is 150, of course.) But the speed gains here are minimal, and we lose flexibility; what happens if we move the playing field at some point in the game’s development? We’ll have to go back and change all those values of 150 to the new value — manually.

You don’t have to optimise every single piece of code. Concentrate on the slowest ones.

Links

There are a lot of quirks to memorise. For instance, value = value / 5 is much slower than value = value * 0.2. Fortunately, a number of awesome people in the community have already listed these:

If you want to run your own tests (and you should), check out Grant Skinner’s AS3 Performance Testing Harness. Lee Brimelow posted a screencast explaining how to use it here.

Got any tips, techniques or links that I’ve missed? Stick them in the comments :)

{ 32 comments… read them below or add one }

grdshch February 11, 2010 at 7:32 am

Michael,
Do you know any performance analyzers for AS3 code such as Intel VTune for other programming languages? It would be very useful for optimizing flash games.

kustrle February 11, 2010 at 7:51 am

I was sure pixel perfect collision detection already first check if two objects are overlaping.
Is there any way of reducing lag that comes from glow, blue, etc without photoshop? Since we lose flexibility there too. If we want to change glow to other color later it will be much harder. Can we tell flash to convert those objects to some kind of bitmap picture and then forgot about all filters?
Great tutorial!

Andreas Renberg February 11, 2010 at 10:55 am

Great info. I was wondering if there were already lists compiled of which things are faster than others, so thanks for the links.

Regarding optimizing lines, I tend to save a commented out copy of the original line right above it, so if I change something in the way the code works, I don’t have to start from scratch and try to figure out what in the world I was thinking when I wrote and then shortened down that line.
For instance:

//if ( player.x > playingField.rightEdge.x )
if ( player.x > 150 )
   { player.x = 150; }

And

//var newX:Number = ( 47 * Math.sin( Math.PI * 23 / 109 ) / 121.88 ) + player.x;
var newX:Number = 0.237317256 + player.x;

Andreas Renberg February 11, 2010 at 2:42 pm

@kustrle – Yes, it is possible to save the “filtered” version of DisplayObjects as BitmapData and use that the entire time.

If all your enemies of a certain look the same, you can apply all the filters before the game starts, however, if each enemy is different in it’s own way, you can apply the filters once they are needed.

This is a little bit of “quasi-code” of how to add a glow filter to an enemy if it is enraged. Flash only needs to calculate the glow once, and since I’m also no longer using vector graphics, it speeds up the rendering time enormously. There are better ways, but this describes it simply.

if (enemy.enraged)
{
   //enemyNormal_bmp is here the currently displayed Bitmap of the enemy
   enemy.removeChild( enemyNormal_bmp );

var enraged_bitmapData:BitmapData = makeEnraged(enemyNormal_bmp.bitmapData);
var enemyEnraged_bmp = new Bitmap(enraged_bitmapData);
enemy.addChild( enemyEnraged_bmp );
}

function makeEnraged( normalBitmapData:BitmapData ):BitmapData
{
//Of course, this code right now is more optimized for readability than speed. :P
var srcBmd:BitmapData = normalBitmapData.clone();
var srcRect:Rectangle = srcBmd.rect;
var filter:BitmapFilter = new GlowFilter();

//Since adding glow makes the image a little larger, figure out the new size
var targetRect:Rectangle = srcBmd.generateFilterRect(srcRect, filter);

//Create the new bitmap data that will be returned
var bmd:BitmapData = new BitmapData(targetRect.width, targetRect.height, true);
bmd.applyFilter(srcBmd, srcRect, new Point(-targetRect.x, -targetRect.y), filter);

return bmd;
}

In fact, there is an entire field of options and projects where people use BitmapData to increase speed and allow more items on the screen, as rendering too many vectors tends to be slow for the Flash Player.

Here are a few links that might point you in the right direction.
EDIT: The spam filter keeps stopping me, so I probably have too many outgoing links.
I posted this same comment (with links) on my blog, so you can reach them there:
http://iqandreas.blogspot.com/2010/02/i-originally-posted-this-as-reply-to.html

I’m in the process of developing a simple “tile game” framework that uses only drawn bitmaps, so keep an eye on my blog for future updates.

Kustrle February 11, 2010 at 4:01 pm

Thanks Andreas.

SergioAwoke February 12, 2010 at 1:10 am

I’m really happy you made this tutorial! Your tutorials are always easier understand.
The recycling idea is very fantastic, mainly for shooter games where there are thousands of enemies and bullets moving.
I usually use the TweenMax ( http://www.greensock.com/tweenmax/ ) to make the blur and glow effect, but now I’ll think about its use.
And it’s very good you alerted that optimizing the game while developing is bad.

One thing I want to talk about: I see that this game ( Mechanical Commando 2 – http://www.kongregate.com/games/BerzerkStudio/mechanical-commando-2 ) has a scrolling system and that the objects that you can’t see are hidden or deleted (you may see it better when playing in low quality). Do you know if it really help to the script speed?

I’m also interested in the post about optimizing for size (reducing MB amount). What I know about this is that the audio files are the main evil.

Cameron Yule February 12, 2010 at 11:13 am

I wouldn’t advise people to optimise code by hard-coding literal values (commonly called magic numbers), as it leads to code that’s a lot harder to maintain.

Imagine taking over a project which contained the line of code in your example:

var newX:Number = 0.237317256 + player.x;

How am I meant to know what the literal value represents?

A better way to solve this problem would be to have each literal value in your expression (47, 23, 109, 121.88) set as constants with names that describe their purpose and abstract the calculation into it’s own method.

The optimisation that you’re trying to achieve could then be accomplished by caching the value of the calculation as a class variable and adding the player.x value within the enter frame loop or wherever it’s required.

.-= Cameron Yule´s last blog: Show redraw regions in Flash =-.

arxanas February 12, 2010 at 2:29 pm

Cool, I didn’t know this stuff before.

Michael Williams February 13, 2010 at 2:21 am

@grdshch: I’ve never heard of VTune before. Can you explain to me what it does?

@kustrle: You’re probably right about PixelPerfectCollisionDetection checking for overlap first. But it’s a good example nonetheless :)

Andreas has already answered your question about glows and so on (thanks Andreas!) — I have a tutorial on blitting which you might find useful coming up soon as well.

@Andreas: Good tip about keeping the old line as a comment!

And yeah, my spam filter is a little overzealous sometimes. Sorry about that.

@SergioAwoke: Thanks :) And thank you for suggesting this post. It’s difficult to say, “you must never do this or your game will be slow;” you really need to look at the whole thing at once and see what will make the most difference. Sometimes you’ll be able to skip obvious optimisations without it having too much of an effect on performance.

Hiding or deleting objects should increase the speed, yes. I’m a little hazy on the details but I think Flash draws objects that are in the display list even if they aren’t on the screen. Or maybe it just does some calculations, but not much. I’ll have to look it up…

@Cameron: I totally agree :) I’d probably define a class-wide var and set its value to ( 47 * Math.sin( Math.PI * 23 / 109 ) / 121.88 ) in the constructor.

@Arxanas: Cheers :)

Andreas Renberg February 13, 2010 at 2:27 am

@Cameron Yule -
Still, calling constants (I believe) still takes a toll on the the speed, especially in a lot of loops, however, it’s definitely a lot faster than recalculating the values each time.

So, are you saying something like this? (I just really like code, and it helps beginners)

//Code executed once
public const PLAYER_X_OFFSET:Number = ( 47 * Math.sin( Math.PI * 23 / 109 ) / 121.88 );
...
//Repeating code in loop
var newX:Number = PLAYER_X_OFFSET + player.x;

Good idea. but check out my comment for another way to make it “easily maintainable” and understandable to other developers
http://gamedev.michaeljameswilliams.com/2010/02/10/optimise-as3-for-speed/#comment-3589

Michael Williams February 13, 2010 at 2:33 am

@Andreas: I think it’s swings and roundabouts here. Yours is faster, but it’s harder to change if you have such magic numbers throughout your code. If I have dozens of lines referencing PLAYER_X_OFFSET then I can just change the value of the definition; if those lines are referencing 0.2376..whatever, then it’s risky to hit Find And Replace in case there are two different constants in play that happen to have the same value.

I suppose one way to get around this would be to do:

var newX:Number = 0.237634/PLAYER_X_OFFSET/ + player.x;

That way, I could find/replace 0.237634/PLAYER_X_OFFSET/ throughout my code and not worry about it affecting anything else.

Michael Williams February 13, 2010 at 2:41 am

Er, asterisks make normal text go italic. So… well, you know what I meant.

grdshch February 14, 2010 at 5:49 pm

@Michael,
VTune is a powerfull code profiler which can tell you how much time your every function takes during the program running. This means that you may detect which functions you should optimize first and which may be ignored.
E.g. if function A() took 20% of execution time and every other function took less then 1% then you need to optimize A() only and may ignore others.

I’ve just found that Flex Builder 3 and Flash Builder 4 should contain embedded profiler. Now I’m downloading Flash Builder 4 Beta 2 release to check it.

Michael Williams February 17, 2010 at 11:14 am

Ah, right. Yep, that sounds like the profiler :) Now you’ve downloaded it, what do you think of it?

SergioAwoke February 18, 2010 at 8:03 pm

I sometimes use the profiling tool of Flash Builder 4, but I don’t get why some functions named with brackets ([ ]) (e.g [render]) are only loaded 1 time and take a long time.

Michael Williams February 22, 2010 at 9:20 pm

Sorry, don’t know anything about that :S

Bigfoot March 18, 2010 at 10:58 pm

Interesting read! If I can ever finish creating a game I’ll put some of these into place :)

.-= Bigfoot´s last blog: Update! =-.

Indiefox April 10, 2010 at 6:03 am

Premature optimization – is evil. Without professional profiling, debuging and well tested library or collection of snippets this may produce unpredictable results in some cases.

Michael Williams April 13, 2010 at 4:40 pm

@Bigfoot: Thanks!

@Indiefox: Yes, definitely. It might feel productive, but it’s just wasteful.

Lorenz April 19, 2010 at 2:38 pm

Very intersting reading, thank you for sharing…
Do you think copyPixels is faster than Draw?

Michael Williams April 23, 2010 at 1:54 pm

Cheers, Lorenz.

As far as I’m aware, copyPixels() is faster, but it really depends on the situation. The best people to ask about this are Jeff and Steve Fulton of 8bitrocket.

Funland.com September 28, 2011 at 3:08 am

I’m developing my first flash game and I see now how performance is really a very big issue. One thing I’ve found out is that you should try using the copypixels function instead of the draw function since it’s a lot faster. And also, you can have separate update and rendering methods so you can still update the game at 60 FPS for example but only render it a 30FPS…

Anyway, great stuff!
Thanks!!

awadh March 13, 2013 at 7:28 am

suppose for fighting game we use a hero character with the bunch of animations together, and finally we play at particular moment….is it best method? or should we need to make all animation separately? and add or remove when when moment require . Pls tell me ….

Benjamin Guihaire August 6, 2013 at 3:01 pm

I would add, do not work on “blind” optimizations, profile your code , by using Adobe Scout for example to discover which portion of the code needs optimizations.

http://www.guihaire.com/code
Ben.

Leave a Comment

Writing code? Write <pre> at the start and </pre> at the end to keep it looking neat.

Anti-Spam Protection by WP-SpamFree

{ 2 trackbacks }

Previous post:

Next post: