Hack 26 Smooth Scripted Motion 
Increasing the frame rate can cause
Flash's rendering engine to hog processor time.
Create visually smooth animations without simply increasing the frame
rate.
One of Flash designers'
worst habits is increasing the frame rate to absurdly high values to
make animations appear smoother. Although this may work in a simple
FLA performing a lone animation, when you are building a larger Flash
movie or site, you shouldn't let screen drawing hog
all the processor time. Setting the frame rate to 95 frames per
second (fps) forces Flash to constantly render images to the screen.
The resulting lack of idle time can make sounds pop and cause delays
in event processing, which can make interactivity appear sluggish.
This hack looks at how beginning Flashers are often taught to animate
and why it isn't always the best solution. Then
we'll look at ways to create smooth animations
without changing the frame rate.
User-Actuated Movement (Breaking the onEnterFrame Monopoly)
In the simplest case of animations created at authoring time, the
Flash playhead progresses through the timeline and displays each
frame in turn. This is so-called
frame-based animation, like a digital
flip book. In such a scenario, the obvious way to increase the speed
of the animation is to increase the frame rate (you can set the frame
rate in the Document Properties dialog box accessible via
Modify Document). When a traditional animator learns Flash,
he feels right at home with these techniques.
But when that same Flasher learns scripted animation, he must change
his mode of thinking. Most beginning scripters are taught to
implement scripted motion using onEnterFrame(
) handlers. In simple cases, in which the
frame rate is not excessive and scripting animation should be tied to
the frame rate, using onEnterFrame( ) is a
reasonable option. But when your animations become more
sophisticated, so must your techniques. Otherwise, performance is
likely to suffer or your creativity is apt to be limited.
Don't fall into the trap of thinking that all motion
graphics should be controlled via onEnterFrame(
) handlers. Because onEnterFrame
events are tied to the frame rate, the easiest way to create smoother
animations is to increase the frame rate, which increases the
frequency of onEnterFrame events. However, if
the user interacts with graphics and animation,
onMouseMove( ) is a far more efficient event handler to
employ. A drag-and-drop feature is a good candidate to be implemented
in an onMouseMove( ) handler. Likewise, features
in which the user controls animation or performs drawing with the
mouse can both be controlled via onMouseMove
events.
Rather than increase the frame rate to make a draggable movie clip
move smoothly, use updateAfterEvent(
) within an
onMouseMove( ) handler to redraw the Stage while
the mouse is moving.
The following code performs a drag-and-drop operation smoothly, even
if you set a low frame rate, such as 1 fps:
function pressHandler( ) {
this.startDrag( );
this.onMouseMove = function( ) {
// Refresh the Stage while the item is being dragged
updateAfterEvent( );
};
this.onRelease = function( ) {
this.stopDrag( );
delete this.onMouseMove;
};
this.onReleaseOutside = this.onRelease;
}
// Create a movie clip and make it draggable
var puck:MovieClip = this.createEmptyMovieClip("puck",
this.getNextHighestDepth( ));
puck.lineStyle(40, 0xCCCCCC, 100);
puck.moveTo(-1, 0);
puck.lineTo(1, 0);
puck._x = 275;
puck._y = 200;
puck.onPress = pressHandler;
Let's review key portions of the code. The main code
(following the pressHandler( ) definition)
creates a small movie clip and makes pressHandler(
) its onPress
event handler. This triggers the action when the user clicks on the
movie clip.
The function pressHandler( ) attaches an
onMouseMove( ) event handler to the movie clip,
which redraws the screen repeatedly as the mouse is dragged. This
arrangement causes Flash to redraw the screen at a higher rate only
when the item is being dragged, giving us smooth movement without
having to increase the frame rate. This implementation is provided to
allow ActionScript 1.0 scripters to focus on the techniques being
taught. Similar drag-and-drop code can be implemented using OOP and
ActionScript 2.0 [Hack #20] .
The same principle can be seen in the following listing. Here, the
onMouseMove event is used to create a simple
Pencil tool. If the onMouseMove event was
changed to onEnterFrame, the event handler would
be running when it is not required (i.e., when the cursor has not
moved).
function penDown( ) {
this.moveTo(_xmouse, _ymouse);
this.onMouseMove = function( ) {
this.lineStyle(null, 0xCCCCCC, 100);
this.lineTo(_xmouse, _ymouse);
updateAfterEvent( );
};
this.onMouseUp = function( ) {
delete this.onMouseMove;
};
}
var drawClip:MovieClip = this.createEmptyMovieClip("drawClip",
this.getNextHighestDepth( ));
drawClip.onMouseDown = penDown;
Final Thoughts
Although the temptation to use onEnterFrame( )
event handlers to animate everything always exists, it is not the
only event that can be used to create animation in Flash. We just saw
a case in which using the onMouseMove event
produced both more efficient and smoother animation. It was more
efficient because it uses less processing power (it refreshes the
screen only when needed), and it is smoother because the frequency of
onMouseMove events (unlike
onEnterFrame events) is unrelated to the frame
rate.
Although using the onMouseMove event applies
only when the user action is related to mouse movement (such as for
drag-and-drop or pen drawing operations), you can look for other
events on which to trigger screen refreshes. For example, you might
update the screen when data is received or when a sound completes.
However, in some cases you may want an animation to be performed over
time. Luckily, onEnterFrame is not the only
time-related event available. When you want to create several
animations that will run at different rates, it is usually better to
use setInterval(
) to create a separate timed event for each
[Hack #27] (rather than use
onEnterFrame for all of them).
|