Improving Performance in your Flashes

A place for tutorials on how to get the most out of Flash

Improving Performance in your Flashes

Postby Renara » Fri Jun 10, 2011 12:51 pm

One of the things that can quickly get on top of you when working in Flash, is performance. Vector Graphics may seem simple in theory, but they can actually be quite demanding to draw, and some common practises in scripting can also increase the demands that Flash has upon a user's system, so I'm going to try and address some of the simpler methods of improving performance here in this thread.

Scripting Issues

Optimising symbols that rarely change
One of the biggest drains in Flash are symbols that rarely change, but need to be re-rendered frequently. The most common examples are scene-backgrounds, as they occupy the whole scene, and are partially redrawn every time something on top of them (such as characters etc.) are updated, or even worse can be scrolling backgrounds that update fully every time they move!

Fortunately there is a dead simple solution to this, in the first frame of your symbol, simply add the following:
Code: Select All Code
this.cacheAsBitmap = true;


Quite simply, this causes the symbol to be rendered into an image, removing the need to continually redraw the vectors. You should use this sparingly, as it won't improve everything, and for rotating or transforming objects it can look significantly worse, however for backgrounds it can greatly reduce the rendering cost, and speed up side-scrollers, even ones where the background is static (doesn't move).

Oh, and don't use this on animating backgrounds! If you have an animated background then try to separate out the animating and non-animating pieces into separate symbols, and apply this feature to the non-animating pieces separately. This will give you the benefit of caching, with the effect of animating. Remember as well that for our purposes, objects that are simply moving without any rotation or transformation are "static", but should be cached separately if they are not moving with the other objects. For example, the illusion of a realistic cloud-layer may use three layers of clouds, one near, one normal, and one far. All three of these can be cached, but should be cached separately, as they will move at different speeds.

It's worth noting that fancy effects such as filters (blur, etc.) will automatically transform any affected symbol(s) to bitmaps. For this reason, if you are using such filters then it is worth being very careful what you use them on, as any animated objects being blurred will kill performance very easily; for such objects it's a good idea to pause their animation (using the stop() function), then perform the blur, and use play() to start them again once the blur effect has been removed.

The other major advantage of this often overlooked feature is that you don't need to do anything to your artwork! You can work with vectors just as normal, and Flash itself will produce the bitmap automatically, so you get the benefits of a vector's low file-size, and crisp-detail, but can keep the performance nice and manageable.

Optimising your vectors
A simple option that not everyone is aware of. After opening a symbol and selecting some or all of its contents, simply go to Modify -> Shape -> Optimise. This handy little tool will attempt to simplify any vectors, while retaining as much of the original shape as possible, usually resulting in a bit of a performance boost by making the shape easier to draw. It's generally good-practise to do this on artwork as you work on it in Flash, and you'll need to try out different settings to get the right balance of optimisation and graphical detail, as optimising all the way can ruin your object(s).

As a general rule, if you're using the above cacheAsBitmap feature, then you don't need to do this. However, for symbols that are commonly used, and cannot be cached as a bitmap (because you want them to rotate, transform etc.) then it's worth trying the optimise tool to see if you can get any improvement.

Scripting Issues

The following are some useful improvements, aimed mainly at optimising ActionScript 2, as ActionScript 3 is built more like a "proper" programming language so these issues are usually covered in most good existing AS3 tutorials and introductions to the language.

Polling in ActionScript
The most common method of creating updating objects in Flash, such as Krystal's changeable mess-layers and armour, is to use a simple loop that checks every frame to see if a variable has changed, and respond accordingly. When a script is periodically checking the status of a value, we call this polling, and it can be extremely costly in terms of performance.

While it's a super-simple method to code, and nice and easy to understand, every single item you add to your Flash that polls for values will increase the cost on performance. So if you have five objects checking then that might not be too bad, but if this increases to twenty objects, then suddenly you're spending four times as much processor power on checking values that don't change all that often! The result is that the more complex your Flash becomes, the more and more checks are being performed, which can result in a lot of wasted time.

Event-based updates
The way to address this is to essentially flip the problem around; instead of your symbols asking for data all the time, we simply give them the data when they need it. This is dead simple in theory, but unfortunately is fairly complex in practise, as your script needs to know which objects are in the scene, and have some way of accessing them. Fortunately some of this can be boiled down into simpler code that, while not really best practise, can start to improve performance by eliminating unnecessary polling.

To start with, in ActionScript 2, you will need a link to the EventDispatcher, now, some guides recommend more complex methods, but the following is a nice simple one. Somewhere at the start of your flash (such as a "play" button on your pre-loader), stick the following:
Code: Select All Code
_root.eventSource = {};
_root.eventDispatcher = EventDispatcher.initialize(eventSource);


You now have an event dispatcher! Simple right? Now, in each symbol you have that needs to know about some important value, simply add something like this in the first frame, making sure that the first-frame does not loop, or if you prefer you can use the onClipEvent(load) event. In this example we're doing a simple handler for a character to detect when/how they are moving:

Code: Select All Code
_root.eventSource.addEventListener("MovingEvent", this); // Copy this line for each event type you're interested in
this.onUnload = function() {
    _root.eventSource.removeEventListener("MovingEvent", this); // Copy this line for each event type you're interested in
}

this.MovingEvent = function(event:Object) {
    if (event.data == "left") gotoAndPlay("left");
    else if (event.data == "right") gotoAndPlay("right");
    else gotoAndPlay("idle");
};

this.MovingEvent({ type: "MovingEvent", data: "idle" }); // Pass in a fake event to make sure the symbol starts with the correct data, point this to a variable for even better results


This is understandably confusing looking, but quite simply the first two lines add the symbol as a listener for a type of event which I've named "MovingEvent", and then creates a function that will handle the event once received. The last line is used to trigger the event right away, so that a moving character will appear to move immediately, rather than waiting until an event is received.

Now, this is all well and good, but to make use of it, we need to actually trigger some events! So, in our movement code we might do something like the following:

Code: Select All Code
if (!player.movingLeft) {
    _root.eventSource.dispatchEvent({ type: "MovingEvent"; data: "left" });
}


This will be received by our character symbol(s), and cause an update accordingly! Suddenly we've removed 20+ checks per second, and replaced it with code that only triggers when an update is actually needed! The if statement is used to ensure we only send events when they're needed, which can improve performance even further.

Detecting Key Presses and Moving Symbols
A common use of the EnterFrame event is to detect key-presses and behave accordingly; however, there are some issues with this, as doing-so every frame can be wasteful when several frames will usually elapse without changes in key-state, so constantly testing the state of each key that you care about can be a drain on performance, especially if you have a complex control system.

In such cases; use of the onClipEvent(EnterFrame) should be restricted to objects that ware capable of movement, testing the simplest possible movement parameters like so:
Code: Select All Code
onClipEvent(EnterFrame) {
    if (this.isMoving) {
        var speed = 0;
        if (this.movingLeft) speed -= 5;
        if (this.movingRight) speed += 5;

        if (speed) this._x += speed;
        else this.isMoving = false;
    }
}

While triggering this event is still a small burden, it's a necessary one in this case, and is greatly reduced by the simple this.isMoving check, which allows the event to exit as quickly as possible. An alternative that is more complex, is to have a central source with an EnterFrame event, that moving objects can attach themselves to, and will in turn have movement commands sent to them on-demand. This way an object that is not moving can simply unregister itself, resulting in it costing nothing while it sits idle; you may wish to consider this method if your game has a lot of moving objects that are capable of being idle.

In any event, once the EnterFrame event has been simplified or removed, we can focus on getting the key presses that we need, and this couldn't be simpler! In much the same way as event-based dispatch of symbol update to replace polling, we can simply do the same thing but with the Key object, like so:

Code: Select All Code
Key.addListener(this);
this.onKeyDown = function() {
    if (Key.isDown(Key.LEFT)) player.isMoving = player.movingLeft = true;
    if (Key.isDown(Key.RIGHT)) player.isMoving = player.movingRight = true;
}
this.onKeyUp = function() {
    if (!Key.isDown(Key.LEFT)) player.movingLeft = false;
    if (!Key.isDown(Key.RIGHT)) player.movingRight = false;
}


Of course this is grossly over-simplified, but hopefully you get the idea! This will likely need a good cover on collision detection, but that's a very complex subject!
Renara (team twitter | newgrounds)
Team Lead Programmer
Lok Team Member
Site Administrator
User avatar
Renara
Foxy Admin
 
Joined: Fri Jan 08, 2010 4:16 pm

Re: Improving Performance in your Flashes

Postby Renara » Fri Jun 24, 2011 10:59 am

Just wanted to note that I've made a massive mistake in the event based updates section, so thanks to Luftmallow who's been struggling along with it and found the issue! Basically I've managed to forget to change a fairly important bit from the code I ripped out to do this, namely that the name of your event-handler should match the type of event it is supposed to receive.

One thing to note, is that you can create an single event handler function for multiple events if you wish, and if you have multiple events doing similar things then it can be a good idea to do this, like so:

Code: Select All Code
// Register your events up here as normal

var eventHandler = function(event:Object) {
    switch (event.type) {
        case "MovingEvent":
            // Do some movement related stuff here
            break;
        case "CollisionEvent":
            // Do some collision related stuff here
            break;
        default:
            trace("Unhandled event type '" + event.type + "'");
    }
};

this.MovingEvent = eventHandler;
this.CollisionEvent = eventHandler;


If your events are doing very different things though, then it's usually best to have separate event handlers, rather than sharing a single one, but that's a decision you need to make for yourself based on the nature of the events themselves.
Renara (team twitter | newgrounds)
Team Lead Programmer
Lok Team Member
Site Administrator
User avatar
Renara
Foxy Admin
 
Joined: Fri Jan 08, 2010 4:16 pm

Re: Improving Performance in your Flashes

Postby Alcander » Mon Jul 11, 2011 4:09 pm

You're a life saver, Ren. Thanks a lot!
I've got a question about something though, somwhere I once caught the idea that commands (such as x=0 or even functions) require less processor power to perform than even listeners, and I'd like to know if that's true.

If so then the script you used in the Original post with the "if(moving)" could be made even simpler by making the moveleft/moveright variables into one variable- a number with left =-1 and right =1, that way all you'd have to do is put a
Code: Select All Code
this._x+=speed*moveDir
without all the ifs(which I consider event listeners as well).

I'm really curious if this would actually improve performance or not.
There are no innocents!
It is all of us, through action and inaction that make the world what it is.
Was I not the one to speak the prophecy?
Would the gods have turned on one another if I had not?
User avatar
Alcander
 
Joined: Thu Dec 16, 2010 4:38 am
Location: Shalebridge Cradle

Re: Improving Performance in your Flashes

Postby Renara » Thu Jul 14, 2011 1:22 pm

Sorry for the delay in replying! I forgot to subscribe to this thread so I didn't notice your post!

Alcander Wrote:I'm really curious if this would actually improve performance or not.

Is this with regards to the key-press segment? That code is really tracking whether the left or right key is being held, essentially deferring the movement calculation until the object is ready to move in its EnterFrame event. The advantage of this is that it guarantees smooth movement, as no values are calculated by the key press events themselves (which can sometimes trigger more than once per frame).

What you pointed out would certainly make most sense in my example, since it's only simple, but when things start becoming more complex, specifically if a character can move without key-presses (for example, due to gravity or enemy attacks) then it's better to keep it separated out.


In general cases; the performance of calling an event isn't all that bad, as Flash uses an engine similar (I believe based-on actually) to Chrome's V8 Javascript engine, which compiles and optimises Javascript, which is essentially what ActionScript is. This means that event calls can be optimised quite effectively, and most basic operations (arithmetic, setting values, conditionals, loops etc.) are all very fast.

The main issue with events is if you don't give them a chance to optimise, for example if you're registering events with an object that isn't around for very long. In these cases it's better to either not call the event at all, or call a single event that can handle all such throwaway objects; particularly things like projects (enemy attacks). But that's another subject for another tutorial, or maybe a good one to add to this one.
Renara (team twitter | newgrounds)
Team Lead Programmer
Lok Team Member
Site Administrator
User avatar
Renara
Foxy Admin
 
Joined: Fri Jan 08, 2010 4:16 pm

Re: Improving Performance in your Flashes

Postby dirtyc101 » Thu Jul 14, 2011 10:45 pm

Speaking of late replies, Hey Ren, thanks for posting this. ;) There's really not a lot of theory out there for how to optimize Flash code for platformers. Or at least, I haven't found much anyway. heh. I'd never even heard of event handlers, so now I have some new terms to search. Yay! (?) Or more likely, I'll come back here & keep re-reading it 'til it makes sense. lol

DirtyC101
dirtyc101
 
Joined: Fri May 21, 2010 10:18 pm

Re: Improving Performance in your Flashes

Postby Renara » Thu Jul 14, 2011 10:50 pm

Hey dirtyc! I know I can be a bit technically minded so if any part of the tutorial is giving you particular difficulty then just let me know, and I can try to come up with some example code that better resembles your use case(s)!
Renara (team twitter | newgrounds)
Team Lead Programmer
Lok Team Member
Site Administrator
User avatar
Renara
Foxy Admin
 
Joined: Fri Jan 08, 2010 4:16 pm

Re: Improving Performance in your Flashes

Postby Hnyarly » Sun Aug 14, 2011 12:47 pm

Hi all:
I've thinking about how to avoid character configuration polling (mainly for people like me, too lazy to study event handlers). That's the way I've just implented in my game.

First, you need a function in the character that checks all the variables related to its configuration (as clothes, skin colour, mess... etc). This function also must show/hide clips in the character depending of those variables.

Second, you need a way to call this function each time one of those variables changes its values. If we were using c++ we could use "Overloading operators" to make sure we call it. But I don't know if AS allows it, so we have to use another approach.

Thus, instead on changing those variables in the usual way, we'd need to define assignment functions. For example: we have "check_config()" function in the character "char" that controls the character's look. "char" has a variable called "eye". (eye==1) means the eye is opened and (eye==2) mean it's closed. So we need to define this function in "char":

function change_eye(i:number)
{
eye=i;
check_config();
}

PS. It's more optimal if you control each moviclip in the assignment function instead of using a function to configure all the character look. Example:

function change_eye(i:number)
{
eye.gotoAndStop(i);
}
User avatar
Hnyarly
 
Joined: Tue Jun 07, 2011 5:11 pm

Re: Improving Performance in your Flashes

Postby dirtyc101 » Thu Aug 18, 2011 10:36 pm

Renara Wrote:
Fortunately there is a dead simple solution to this, in the first frame of your symbol, simply add the following:
Code: Select All Code
this.cacheAsBitmap = true;


Quite simply, this causes the symbol to be rendered into an image, removing the need to continually redraw the vectors.


If I have a movieclip built from other smaller clips, does this code need to be in the smaller clips as well?
Is there a way to check & see if it's being applied correctly?

The reason I ask is my backgrounds are usually made from a series of static movieclips. I just drag them onto the workspace until I get the background I want. I noticed an increase in my framerate when I added this code to each movieclip. However, my game also zooms in & out a bit, and this method slows the game tremendously during zooms. I was thinking I might get some bonus speed by combining all the small movieclips into one big movieclip, and then converting that into a bitmap. However, this doesn't seem to have any effect at all. Zooms look fine, but there doesn't appear to be an increase in speed either.

Many Thanks
DirtyC101



EDIT: Couldn't wait, so I built myself a quick FPS counter & ran some tests myself. Looks like adding this code works just fine, regardless of whether or not there's more clips nested inside the main clip. When I first added this, I saw some gigantic improvements, but I haven't been able to replicate them since. I'm starting to think it was more a lucky fluke than anything. Ah well, still a minor improvement, so thanks for the tips. =)
DirtyC101
dirtyc101
 
Joined: Fri May 21, 2010 10:18 pm


Return to Tutorials



Who is online

Users browsing this forum: No registered users