A financial budget tells you where you are spending your money. Create a performance budget to understand and adjust where you are expending resources.
We saw earlier how to estimate download times [Hack #66], allowing you to cram the maximum presentation into the smallest filesize. Performance has a lower priority in the Flash Player design than does filesize optimization, which means that although Flash allows you to create compelling content in very few kilobytes, you have limited resources from which to extract performance. Although the total processor cycles available to the Flash Player are limited, you can control where Flash spends its time. A performance budget reflects a conscious effort to adjust the amount of time Flash doles out to each of the parts of your movie.
Like all budgets, your performance budget should include priorities. That is, not all aspects of your presentation are equally important. For example, users notice hiccups in audio tracks more than hiccups in videos or animation. Designers also tend to lavish attention on things the typical user won't ever notice or appreciate. The user generally looks closely only at the things she is currently interacting with; elements within the user's "area of focus" get the greatest attention from her and therefore should be given priority in your performance budget. Items in the user's peripheral vision may be ignored entirely or noticed only when they do something unexpected, such as shift by a pixel. Therefore, allocating your performance budget and designing an interface that serves the user's needs are complementary tasks.
If you can anticipate (or control) the user's area of focus, and make that perform well, the user gets the impression of greater overall performance even if peripheral items are static or perform less well.
For example, in video games (and intensive real-time graphics), items closest to the viewer in the 3D virtual world are rendered with the most detail. The detail can drop off significantly with distance; even if the player notices, it mirrors reality in which things further away are generally less visible/detailed. Likewise, the collision detection algorithm [Hack #40] used by distant parts of the game can be less precise for the same reason?they are not close enough to be in the user's area of focus. This allowance frees up some of the performance budget for real-time lighting, physics, and other trappings of virtual worlds.
There are a number of ways to give your area of focus the lion's share of the performance budget. The easiest approach is to simply give the area of focus an "on-change" event handler and use a periodic event to update the rest of the movie. For example, if you are implementing a pong game, you can use an onMouseMove( ) event handler to control the user's paddle and an onEnterFrame( ) event handler to control the opponent's paddle and the ball. If the part of the game that the user controls is responsive, the entire application feels more responsive.
However, just setting two different priorities doesn't allow us detailed control over the performance budget. A better approach is to use several different priorities. Here we allocate our priorities based on the likelihood and directness of user interactivity:
Processes with which the user will interact directly
Processes with which the user will interact indirectly
Processes with which the user will rarely or never interact
In terms of a game (the most common high-performance Flash application), the high-priority process is the player's ship or character (a.k.a. token). Normal-priority processes include the enemy graphics; although the user expects them to move at an adequate speed, the slowdown won't be as noticeable as long as the high-priority stuff doesn't slow down as well. The user will just assume that the slow-moving enemy target is supposed to move slowly.
Low-priority processes are things like the score update or a scrolling background?the user notices if they break, but if they work adequately, the user pays little attention.
Low-priority processes can be hard for game designers to identify because developers are personally vested in every pixel and audio cue. You'll be more apt to let go of your rigidly held beliefs if you realize that everything you deprioritize allows you to lavish more attention (or performance) on things that matter more. And don't forget that the sound effect that was cute the first time might get really boring after the user hears it a thousand times. So the best option is to put your prototype version in front of beta testers. Ask them what they like, what seems too slow, what they find annoying, and so on. By definition, these are the people you are trying to entertain, attract, or serve, so listen to their feedback.
You can also trick your audience into thinking you are doing more than you actually are. For example, you can have a scrolling star field with many stars when the game is displaying the static high score table, but as soon as the game starts, you can reduce the animation complexity [Hack #70] . The user won't notice if you slowly drop the number of stars as the game gets faster and more difficult. He is more likely to be concentrating on getting to the next level!
Once you decide on your priorities, you need to implement them in ActionScript. Since you can't just tell Flash that something is important, you instill priorities indirectly via the programming techniques and events you choose.
High-priority events can use either:
An interval (created with setInterval( )) set to a period shorter than the frame rate [Hack #27]
An onMouseMove( ) event handler [Hack #26]
Because high-priority events occur more frequently than the frame rate, the high-priority event handlers must include an updateAfterEvent( ) command to redraw the Stage between frames.
Normal-priority events can use an onEnterFrame( ) event handler to perform operations at the same frequency as the frame rate.
Low-priority events can use either:
An interval (created with setInterval( )) set to a period longer than the frame rate
A listener event that is occasionally triggered from a normal-priority event's onEnterFrame( ) handler
Figure 9-8 shows the interface for a scrolling video game. In this example, we'll set different priorities for different aspects of the game.
game01.fla from this book's web site shows the main routine for a typical FLA configured using a performance budget philosophy; look at the script on frame 2 of the movie clip mc.world for the main listing.
Although ActionScript purists might balk at the fact that a script is attached to a movie clip, game design is as much about animation as it is scripting, so you will find animation mixed with code, and very rarely will you find an entire game on a single frame. For example, if you look at the player's ship (symbol mc.ship in the Library), you will see that the explosion sequence is a keyframe animation rather than 100% scripted. Although you could use scripted timers to control the explosion animation, the timeline animation is easier to create, requires little forward planning, and is more likely to be comprehensible to designers who might have to edit it.
Here is how the three sets of priorities are handled in the FLA file's code.
The ship sprite is the only high-priority process. The following code sets up an interval that invokes shipController( ) every 30 milliseconds to redraw the ship:
shipControl = setInterval(shipController, 30);
The background terrain update has a normal priority (to be updated at the frame rate of 18 fps), so it is scrolled every frame by setting the onEnterFrame( ) handler to terrainController( ):
terrain.onEnterFrame = terrainController;
The score update is low priority, so it is refreshed only once per second:
scoreKeeper = setInterval(scoreController, 1000);
You can also see how the system works by simply playing the game (a far better option!). You will notice that:
The star field scrolls more slowly than the terrain. The stars are assigned a low priority and update every quarter of a second. This fact is hidden somewhat by staggering the update?each star animates once every quarter second, but not all of the stars update at the same time.
The radar display updates at around the same rate as the stars. The game is designed to make the slow update seem intentional?the old cathode ray tube radars worked on a slow scan update. A common trick is to fill blank areas of the screen with things that the user expects to move slowly, such as clouds and distant hills. The slow updates for these items seems natural.
The player's ship moves much faster (and more smoothly) than the aliens. Most users won't perceive the difference because they are focused on their own ship. If they notice the difference, they are happy to be able to outmaneuver their sluggish enemies.
The aliens, laser, and terrain all move at the frame rate.
The score updates very slowly (every 1 second). This is the lowest-priority process in the game because the user is busy looking elsewhere. Updating text fields too frequently is one of the biggest performance killers in Flash. Even a modest amount of text takes a lot of vectors to draw, especially if Flash is redrawing it every frame!
This game example shows it is possible to create a fast Flash game with a reasonably large Stage size. Increasing the size of the browser window need not kill performance if you structure your games properly.
Using a performance budget doesn't make the Flash Player faster, but it gives the perception of faster performance, just as a preloader status bar makes the user feel as if the download is faster. You should identify the elements that need to update frequently and allocate more of the available performance budget to them. Likewise, identify the low-priority processes and run them more slowly to make more time available for higher-priority processes. If you increase the performance in the user's areas of focus, the game will feel responsive and the user won't notice the areas of slower performance.