- Home
- Articles
- Best Practices
- Flash Hacks

Adjust the Animation Complexity Dynamically
Sham Bhangal
Sham Bhangal is an author of and contributor to numerous books on Flash and ActionScript, including Foundation ActionScript for Flash MX, Flash MX Designer's ActionScript Reference, and Macromedia Flash MX Upgrade Essentials.
View all articles by Sham Bhangal
|
Copyright © 2004 O'Reilly Media, Inc. All Rights Reserved. |
![]() |
| This content is excerpted from the above-named O'Reilly publication, with permission, by agreement with ActionScript.org. | |
|
|
|

|
|
Measure the Flash Player's runtime performance in order to adjust the complexity of an effect or animation dynamically to run optimally on both low-end and high-end machines.
In the preceding hacks, we've seen ways to improve performance, regardless of the playback system, by optimizing a Flash movie's assets at authoring time. Optimization of that sort is essentially a lowest common denominator affair. This hack addresses the need to maximize animation and other effects for faster machines without creating a movie that bogs down on slower machines.
Although Flash Player 7 performs better than previous versions, it is still not a speed demon. The underlying goal of Flash is to optimize filesize (i.e., reduce download time) rather than provide breathtaking performance. Although we can improve performance by lowering the render quality [Hack #67], in many cases, turning off antialiasing can result in an unacceptably poor appearance for your site.
A better way to improve performance is to adjust the complexity (i.e., how much is happening per frame) of a graphical effect rather than its quality or frame rate. This approach can yield better results over a wider range of user systems with varying processing power than a one-size-fits-all optimization.
Adjusting the complexity is often an iterative process based on experimentation (with time it will become second nature and require fewer iterations):
Start with a target frame rate, such as 18 fps.
Measure the achieved frame rate, as covered shortly.
If the desired frame rate is not achievable on the test machine, reduce the complexity of the effect.
If the effect is rendered quickly enough, you have the leeway to increase the complexity of the effect.
Now that you understand the basics of the approach, let's automate it so that Flash decides dynamically whether to reduce or increase the complexity of the animation. This approach protects against sluggish performance on slower machines and (when done well) enhances the effect on faster machines.
We do not intend to change the frame rate, but rather change the complexity of the effect, in such a way that it always completes just before the next frame starts.
The following code creates an empty movie
clip called
perfMon
(performance monitor) and attaches an onEnterFrame(
) event handler to it. This event handler calculates the
average frame duration (in milliseconds) using the last two timer
measurements, creating a rolling average. This rolling average,
time, is compared against the expected duration,
FRAME_DUR, and a Boolean flag,
slow, is set to true or
false based on whether the Flash Player is
achieving the target frame rate.
function performanceMonitor( ) {
this.createEmptyMovieClip("perfMon", 10000);
perfMon.onEnterFrame = function( ) {
time = (getTimer( ) - lastTime) / 2;
lastTime = getTimer( );
// Set <em class="replaceable"><code>slow</code></em> to a Boolean based on whether the
// elapsed time exceeds the allowed frame duration
slow = time > FRAME_DUR;
};
}
// Set FRAME_RATE to match the movie's target frame rate
var FRAME_RATE:Number = 18;
var FRAME_DUR:Number = (1 / FRAME_RATE) * 1000;
var time:Number = 0;
var lastTime:Number = getTimer( );
performanceMonitor( );
A slow value of false indicates
that we can make the Flash Player do more without compromising
performance because it is completing all its tasks before the start
of the next frame. Ideally, we would want the Flash Player to finish
all tasks for the current frame just as the next frame starts. We
know this is happening when our rolling average,
time, is equal to the expected frame duration,
FRAME_DUR.
Let's see how to make Flash increase or decrease the
animation's complexity based on the performance
monitor's calculation. One simple approach is to
draw more or fewer movie clips depending on the value of our
slow flag. For the sake of example,
let's use a star field particle effect [Hack #33] . The following code assumes a
default Stage size of 550 400 pixels, with a dark background color.
The effect works best with a frame rate of 18-24 fps. To set the
background color and frame rate, select Modify?Document and
adjust the properties as desired. The following code assumes a frame
rate of 24 fps, and if you choose any other rate, you will need to
change the following line to reflect this:
var FRAME_RATE:Number = 24;
Note that you have to do this manually because there is no property or method in Flash that returns the movie's target frame rate (strange but true!).
We've modified the starfield(
) function from [Hack #33] to draw a single star at a
time. Instead of setting the slow flag when the
animation is running slowly, we use an if
statement to adjust the animation's complexity. If
the animation is running quickly enough, it draws additional stars by
calling starfield( ); otherwise, it deletes
stars to maintain performance.
Again, it is important to realize that we are not varying the frame rate (and doing so would not be transparent to the rest of the SWF, in any case), but rather the complexity of the animation so that the time taken to render each frame in the animation is equal to all the available time per frame.
function performanceMonitor( ) {
var perfMon:MovieClip = this.createEmptyMovieClip("perfMon", 10000);
perfMon.onEnterFrame = function( ) {
time = (getTimer( ) - lastTime) / 2;
if (time < (FRAME_DUR)) {
// Speed is okay
stars++;
starField( );
} else if (time > (FRAME_DUR + 10)) {
// Running too slowly
_root["star" + stars].removeMovieClip( );
stars--;
}
lastTime = getTimer( );
};
}
function mover( ) {
this._y += this.speed;
this._yscale += this.speed;
if (this._y > 275) {
this._y = 0;
this.speed = Math.ceil(Math.random( ) * 10);
this._yscale = 100;
}
}
function starField( ) {
var star:MovieClip = this.createEmptyMovieClip("star" + stars, stars);
star._rotation = Math.random( )*360;
star._x = 275;
star._y = 200;
var dot:MovieClip = star.createEmptyMovieClip("dot", 0);
dot.speed = Math.ceil(Math.random( ) * 10);
dot.lineStyle(1, 0xFFFFE0, 100);
dot.moveTo(0, 2);
dot.lineTo(0, 5);
dot.onEnterFrame = mover;
}
// Set FRAME_RATE to match the movie's target frame rate
var FRAME_RATE:Number = 24;
var FRAME_DUR:Number = (1 / FRAME_RATE) * 1000;
var time:Number = 0;
var lastTime:Number = 0;
var stars:Number = 0;
performanceMonitor( );
If you run the preceding code, you will see the star field build from no stars up to a maximum of several hundred stars, as shown in Figure 9-7. Use the Variables tab in the Debugger panel to view the variables on the main timeline, which displays results similar to those shown in Figure 9-7


