Editor's note: Today we offer two more hacks excerpted from O'Reilly's Flash Hacks. Learn how to create a performance budget that shows where your money is going, and how to secure your online Flash content. And if you missed them, be sure to check out last week's hacks from the book.
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 , 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 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 . 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:
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
shows the interface for a scrolling video game. In this example, we'll set different priorities for different aspects of the game.
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
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.
Make it difficult for others to steal or reverse-engineer your online Flash content
Your carefully honed Flash designs may not be as safe from theft as you'd like to believe. For example, the URL Action Editor (http://buraks.com/uae) allows someone to change the arguments of any URL-based actions that a SWF uses. Someone could take a SWF that loads in your content and rework it to load in his content, or worse yet, pass of your content as being his own.
In at least one clear-cut case, a well-known designer decompiled the code of another well-known designer and passed it off as his own on a resource site. (Hint to the thief: next time, change the variable names to avoid suspicion!)
The Flash authoring tool allows anyone to load an unprotected SWF directly. You can protect your SWFs from import into Flash by checking the Protect From Import checkbox (under File→Publish Settings→Flash tab). However, other applications (such as a text editor) can still open your file, and decompilers such as ActionScript Viewer (http://buraks.com/asv) can unset the protected flag so that it can be imported back into Flash. Compressing the SWF (File→Publish Settings→Flash→Compress Movie checkbox) helps obfuscate your work because the compressed data is harder to decode than the raw SWF.
Technological protection is never foolproof. A clever cracker—we reserve the term "hacker" for innocent tinkerers such as ourselves—can break any protection scheme given enough time. The trick, therefore, is to present the cracker with sufficient obstacles—each one making the solution more obscure and time-consuming—so that he simply gives up.
Games and commercial applications often use a single protection scheme they consider unbreakable, but crackers seem to enjoy the challenge. And the Flash Player browser plugin must ultimately display the SWF content. So if you are going to publish your SWFs, they are unencrypted on the user's machine, even if you serve them from an HTTPS server. Even if browsers supported encrypted playback, a resourceful cracker could capture the images as they are sent to the video card or the audio as it is sent to the sound card.
So our first technique is obfuscation. The aim is to dissuade or delay the cracker by hiding the nature of the protection scheme rather than using an obvious mechanism that seeks to be 100% secure.
We know that all the files for our site will end up in the cracker's browser cache. To find a SWF file or MP3 file, the cracker simply has to look for the right filenames. To make life difficult for the cracker, even at this initial stage, change the file extensions and filenames of crucial files.
For example, consider a streaming MP3 file asset loaded at runtime:
my_sound = new Sound (this); my_sound.loadSound ("song.mp3", true);
Suppose you are writing a Flash-based music jukebox for a recording artist. To avoid a cracker finding your MP3 file and immediately putting it in his Napster/WinMX file-sharing folder, simply change the MP3's filename to an obfuscated name such as top_header_02.gif and modify the code to read:
my_sound = new Sound (this); my_sound.loadSound ("top_header_02.gif", true);
Flash ignores file extensions when loading external files (it assumes that you are loading a sound file regardless of the filename and file extension passed to the Sound.loadSound( ) method). Unless the cracker's operating system looks at the files' contents to confirm file extensions are as advertised (and the last computer I used able to do this was the Commodore Amiga!), he cannot easily determine the file's type.
Readers who have done traditional web design probably already have a big wide smirks thinking about the downright dirtiness of this hack, but here's a rundown for everyone else.
When the cracker looks in his browser cache for any useful media goodies, he will see top_header_02.gif and:
He will most likely not even look at it further, because its name implies a rather mundane GIF slice for an HTML table.
If he decides to open it, his GIF-reading software will tell him it is a corrupt GIF file, and he will most likely give up.
If the cracker starts looking at the domain and time properties of each file in the browser cache or has specifically saved the whole web page and its embedded media (in IE this can be done using File→Save As), he may smell something fishy. Even once he is onto the trick, it may take a long time for him to realize the so-called GIF is in reality an MP3 file. The altered file extension will wrong-foot both the cracker and his operating system. He has to be prepared to open every file in the site to find a file to steal, or he has to decompile the SWF and look for, say, loadSound( ) commands.
If you are feeling particularly evil (and this is a real hack from the dark side), you can rename the filenames using system file types that would tend to crash the cracker's operating system if he double-clicked them. Windows actually warns users who try to fish around in the browser cache that double-clicking on anything there could have dire consequences, so consider your victim to have had fair warning. Naturally, some of these techniques don't apply directly to the Mac OS, but changing the file extensions will confuse crackers on both platforms.
WARNING: If you use this hack, keep a record of each file's true type. Keep your "dummied file versions for upload" separate from your development files. Make sure you have a backup policy because the protection may backfire on you one day when you're the one who needs to decompile the SWF.
The designer who takes inspiration from your work is doing nothing wrong. Even if you do not take this as a compliment, there is little in law and reality you can do about it. You can copyright your expression of an idea but not the idea itself. Although a utility patent can protect an idea, most ideas are not unique enough to be patented, and applying for patents is too expensive and time-consuming to be of practical use. In many cases, even patents offer little protection. A little-known class of patents called design patents can protect designs such as the shape and translucent color case of the original iMacs. But even Apple's legal department couldn't prevent PC manufacturers from quickly imitating the product design.
Although your content theoretically enjoys copyright protection the moment you put it in tangible form, and you can register your copyright for marginal extra benefit, it is next to impossible to enforce copyrights in an international medium such as the Web. And in most cases of misappropriated Flash designs, there is no provable economic damage from copyright infringement, so there is little restitution to be recovered and little use in crying foul.
A better route is the technical one, mixed with a little social engineering. If a cracker wants to save time by using your assets, the trick is to make stealing your content take so long as to not be cost effective.
View catalog information for Flash Hacks
Return to the Web DevCenter
Copyright © 2009 O'Reilly Media, Inc.