Motion: Chapter 7 - Learning ActionScript 3.0
Pages: 1, 2, 3, 4

Zeno's Paradox

Another way to add friction to object movement is to use Zeno's paradox, which says that, when moving from one point to another, you never really reach your ultimate destination because you are dividing the remaining distance with every movement. If you divide the distance between point a and point b in half with every step, theoretically, you could never reach point b. Philosophy aside, this idea can be used to slow down an object as it approaches its destination, as illustrated in Figure 7-9.

Example
Figure 7-9: Zeno's paradox, a simple way to depict friction or easing

This is especially handy when you simply want to add basic deceleration between two points and don't need a more elaborate system. The following example starts by creating a ball movie clip from the library, and then calls the onLoop() function every enter frame. onLoop() updates the movie clip's x and y coordinates separately by calling the velFriction() function, passing in the origin location, destination location, and number of times you want to divide the distance traveled.

1  var ball:MovieClip = new Ball();
2  ball.x = ball.y = 100;
3  addChild(ball);
4
5  addEventListener(Event.ENTER_FRAME, onLoop, false, 0, true);
6  function onLoop(evt:Event):void {
7       ball.x += velFriction(ball.x, mouseX, 8);
8       ball.y += velFriction(ball.y, mouseY, 8);
9 }
10
11 function velFriction(orig:Number, dest:Number, coeff:Number):
   Number {
12     return (dest-orig)/coeff;
13 }

The velFriction() function calculates the difference between the origin and destination point values and divides the result by the number of steps used to close the distance. Note that, despite the commonly stated form of Zeno's paradox, you do not always have to cut the distance in half using two steps. In fact, this is how you vary the animation's deceleration. Higher numbers require more time for the object to reach its destination, and lower numbers finish the animation more quickly. This value can be thought of as a friction coefficient.

As is true of many examples in this chapter, you may want to add a tolerance factor to this system in your own projects. For example, you may want to use a conditional that removes the event listener when your movie clip comes close enough to your destination so you eventually do reach your destination. A variant on this optimization technique is used in the section at the end of this chapter.

Elasticity

Another property of physics that can liven up animations is elasticity. Elastic properties can be applied to spring simulations, of course, but can also be used as another easing method.

Elasticity is easily calculated using Hooke's law. Hooke's law says that the force exerted by a spring is linearly proportional to the distance it is stretched or compressed. It is expressed with the formula F = −kx. F is the resulting force, −k is a spring constant, indicating the strength of the spring, and x is the distance to which the spring is deformed. (Although not vital to this discussion, the equation is expressed as a negative because the force expressed by the spring, often called a restorative force, is not in the same direction as the force applied to the spring.)

The following example uses elasticity to settle a movie clip into each new location. The movie clip moves from a starting position to wherever the mouse is moved, bouncing around the destination until settled, as seen in Figure 7-10.

Example
Figure 7-10: A basic depiction of easing using Hooke's law of elasticity

The script starts by creating a movie clip and initializing x and y velocity variables. It then creates an enter frame listener that calls an elasticity function in lines 10 and 11 that determines both the x and y velocity, and increments the x and y positions of the ball over time. The elasticity function is called separately for x and y values, allowing greater flexibility in which property to affect. For example, to calculate the force of a spring in a cylinder, you might want to affect only the y value, rather than both x and y values. Passed to the function in lines 10 and 11 are the movie clip's starting and ending positions, the spring constant, a damping factor (both of which will be explained in a moment), and the current x and y velocities. Finally, the x and y locations of the movie clip are updated with the newly calculated velocities.

1  var ball:MovieClip = new Ball();
2  ball.x = ball.y = 100;
3  addChild(ball);
4
5  var xVel:Number = 0;
6  var yVel:Number = 0;
7
8  addEventListener(Event.ENTER_FRAME, onLoop, false, 0, true);
9  function onLoop(evt:Event):void {
10      xVel = velElastic(ball.x, mouseX, .14, .85, xVel);
11      yVel = velElastic(ball.y, mouseY, .14, .85, yVel);
12      ball.x += xVel;
13      ball.y += yVel;
14  }

All that remains is the elasticity calculation itself. The velocity with elasticity is calculated first by employing Hooke's law. The elastic force is determined in line 16 by multiplying the spring constant (the strength of the spring) by the distance between the starting point and the mouse location (the distance the fictional spring is stretched). This elasticity is compounded using the += operator so the value can vary with each new position of the movie clip and/or mouse. Because springs don't have infinite energy, the elastic force is dampened every time the function is called, exerting only 85 percent of the last force value on the current elasticity until the springiness is reduced to nothing.

15  function velElastic(orig:Number, dest:Number, springConst:Number,
    damp:Number, elas:Number):Number {
16      elas += −springConst * (orig − dest);
17      return elas *= damp;
18  }

Section 7.4: Programmatic Tweening

When you need a relatively simple animation and don't want to spend time and effort coding it yourself, you may be able to use Flash's built-in Tween class. An example file called as_tween.fla can be found in the accompanying source code. The Tween class allows you to specify the compatible display object and property you wish to tween, the precreated easing function that will affect the property change, the beginning and finishing values of the property, the duration of the tween, and, finally, whether to use seconds or frames when evaluating the tween's duration. Here is a look at the class's constructor.

Tween(obj:Object, prop:String, func:Function, begin:Number,
     finish:Number, duration:Number, useSeconds:Boolean)

The following example creates a ball movie clip, places it at point (100, 100), and then creates the tween. It alters the x coordinate of the movie clip, using an elastic easing. It begins at position 100 and finishes at position 400, and it takes 3 seconds (indicated by the true value of the last parameter, useSeconds) to complete the tween.

1  import fl.transitions.Tween;
2  import fl.transitions.easing.*;
3
4  var ball:MovieClip = new Ball();
5  ball.x = ball.y = 100;
6  addChild(ball);
7
8  var ballXTween:Tween = new Tween(ball, "x", Elastic.easeOut, 100,
   400, 3, true);

Note: In this case, if the last parameter was false, the tween duration would be measured in frames. Considering a tempo of 20 frames per second, a frame equivalent of 3 seconds would be 60.

Because a single tween instance controls a single property, it is possible, and quite common, to create multiple tweens for the same object. They don't even have to have values that keep pace with other related Tween class instances. For example, adding this new emphasized line (line 9) to the previous script will fade in the ball movie clip from a value of 30 percent to 100 percent across the same 3 seconds, but in a linear process with no easing effect.

9 var ballAlphaTween:Tween = new Tween(ball, "alpha", None.easeOut,
                          .3, 1, 3, true);

The Tween class has several additional properties, methods, and events for use by each instance of the class. Notable properties include the Booleans isPlaying and looping (indicating whether the animation is in progress and looping, respectively), and the Number position. The position property indicates the current value of the tweening property, so it refers to the current position of the tween, not the x/y position of the display object on stage—that is, the ballAlphaTween instance seen previously still reports the position variable, even though the alpha value of the movie clip is being tweened.

Available methods include several navigation options, which command the tween to stop, start, and resume playback, jump to the next, previous, first, and last frames of the animation, and play only until a specified point in the tween is reached. Events associated with the tween are fired when the animation is started, stopped, or resumed, when it loops or finishes, and even during the animation each time the screen is updated.

Select the easing class to use via the fl.transitions.easing package. Although specifying an easing class is required, one of the available options is None, so you don't have to apply an easing effect to your tween. The names and descriptions of available easing classes can be found in Table 7-1.

Table 7-1: Easing types found in the fl.transitions.easing package
Easing ClassDescription
BackEasing in begins by backing up and then moving toward the target. Easing out overshoots the target and backtracks to approach it.
BounceBounces in with increasing speed, or out with decreasing speed.
ElasticUndulates in an exponentially decaying sine wave, accelerating in and decelerating out.
NoneLinear motion without easing.
RegularNormal easing, like that found in the timeline's simple easing feature, accelerating in and decelerating out.
StrongEmphasized easing, stronger than that found in the timeline's simple easing feature, but without additional effects. Accelerates in and decelerates out.

Each class has a minimum of three methods to cover easing in, easing out, and easing both in and out of the tween. All methods for each class support initial and final values of the property being animated, the duration of the easing, and the current time in the animation. Back also supports a value for the degree of overshoot beyond the target at the start and/or end of the animation, and Elastic adds support for the amplitude and period of the sine wave used to calculate the elasticity.

Section 7.5: Timeline Animation Recreations

While this isn't entirely an ActionScript solution, we'd like to cover Flash CS3's new Motion and Animator classes. These classes, and their supporting players, make it possible to replay animations that have been created previously in the timeline. Scripting purists may be more interested in perfecting their ActionScript skills than relying on the timeline to originate animations. However, this capability may be attractive to many Flash CS3 users, even coding curmudgeons, for two reasons.

First, it doesn't ultimately use the timeline but still makes it possible to reproduce complex animfations created there—including animations that might not be that easy to achieve strictly with ActionScript. Second, it offers a new path to improved designer-programmer collaboration. Designers can create timeline animations, and programmers can integrate that work into other projects without relying on the original timeline structure.

The foundation of this process exists in a feature called "Copy Motion as ActionScript 3.0." After creating a timeline tween, you can select the entire tween and then choose the Copy Motion as ActionScript 3.0 menu option from the EditĘTimeline menu. This copies to the clipboard all necessary information to recreate the tween with code. During the copy process, the feature prompts you for the tweened symbol's instance name with a convenient dialog—prepopulated if the instance name already exists.

Once the copy completes, you can paste the results in the Actions panel. All the ActionScript needed is included, and the motion is represented by XML information in the format required by the Motion class. A simple example, tweening a movie clip across the stage over 20 frames, follows:

1  import fl.motion.Animator;
2  var ball_xml:XML = <Motion duration="20" xmlns="fl.motion.*"
   xmlns:geom="flash.geom.*" xmlns:filters="flash.filters.*">
3      <source>
4           <Source frameRate="12" x="50" y="50" scaleX="1" scaleY="1"
            rotation="0" elementType="movie clip" instanceName="ball"
            symbolName="Ball">
5             <dimensions>
6                  <geom:Rectangle left="−10" top="−10" width="20"
                   height="20"/>
7              </dimensions>
8              <transformationPoint>
9                  <geom:Point x="0.5" y="0.5"/>
10              </transformationPoint>
11          </Source>
12      </source>
13
14      <Keyframe index="0">
15          <tweens>
16              <SimpleEase ease="0"/>
17         </tweens>
18     </Keyframe>
19
20      <Keyframe index="19" x="450"/>
21  </Motion>;
22
23  var ball_animator:Animator = new Animator(ball_xml, ball);
24  ball_animator.play();

Looking over the generated XML, you can pick out properties such as duration, frameRate, x and y coordinates, scale, and rotation. Also included are the display object type (movie clip), its instance name, and information about its dimensions, registration point, and transformation point. Finally, data about each keyframe is cited, including in which frame each resides, what kind of easing is used, and any information that has changed from keyframe to keyframe. In this case, only the x coordinate has been tweened, so the second keyframe itemizes only this property.

Note: The Keyframe property lists frames 1 and 20 as 0 and 19 because it stores the keyframes in an array, and ActionScript arrays are zero-based. For more information about arrays, see Chapter 2.

As you can see, everything you need to reproduce the tween is included in the XML, here stored in the variable ball_xml. The last two lines of this example include the instantiation of the Animator class, passing in the XML and target movie clip instance name. This class is responsible for playing back the animation, which occurs in line 24. To see the feature work, you can remove the tween from the timeline, place a movie clip with the same instance name on the stage, and test your movie.

Note: The properties copied and applied in this process are relative to the existing movie clip, so the x coordinate updates, for example, will start from the existing location of the movie clip.

This workflow is obviously not something you can carry over to runtime. However, you can do better. With the entire tween selected, you can use the Export Motion XML command found in the Commands menu. This saves the Motion XML only, without the ActionScript that accompanies the copy-paste workflow, into an external file. From there, you can build an Animator player all your own.

The following example reproduces a motion guide tween that traces the word "Flash" in script, with a ball movie clip. The original motion guide, which is the path the Animator class will retrace, can be seen in Figure 7-11. The figure shows two copies of the word because you later can use ActionScript to scale the animation, tracing the word at either size. The XML file needed to recreate this tween is quite long, so it cannot be reproduced here. However, the original file, handwriting.fla, is with the book's source code on the companion web site, and the animation has already been exported to handwriting.xml for easy download.

Example
Figure 7-11: The motion guides used to create a tween that is recreated with the Animator class

This example creates a player that controls playback of the original animation in a new file. It requires nothing more than a movie clip to animate, and the Button component, which we'll use to create the controller buttons.

The first 10 lines of the script import the necessary classes, declare the needed variables, and create and position a ball movie clip from the library, but does not yet add it to the display list.

1  import fl.motion.*;
2  import flash.geom.*;
3  import fl.controls.Button;
4
5  var anim:Animator;
6  var isPaused:Boolean;
7  var isScaled:Boolean;
8
9  var ball:Sprite = new Ball();
10  ball.x = ball.y = 80;

The next segment covers the loading, and response thereto, of the external XML file. We'll cover this in greater detail in , but here's the essence of the matter. All URLs are handled consistently, passing through the URLRequest class. This class captures all HTML information, like MIME types, headers, and so on. In this case, we need only the URL file path to pass to the URLLoader class.

The information the URLLoader class loads can be text, raw binary data, or URL-encoded variables. In this case, the XML document is loaded as text. The event listener in line 13 reacts when this information has been completely loaded by calling the xmlLoaded() function.

11  var xml_url:URLRequest = new URLRequest("handwriting.xml");
12  var xml_loader:URLLoader = new URLLoader(xml_url);
13  xml_loader.addEventListener("complete", xmlLoaded, false, 0, true);

The xmlLoaded() function converts the loaded text to XML and instantiates the Animator class, passing both the XML and ball movie clip instance to the class. From this class, the motion object can provide information about the XML data that has been loaded. Because we know that the original tween includes color as well as position, we add line 17 to query the color in the first keyframe of that motion data, and set the initial color of the ball movie clip to that same color. This prevents the movie clip from appearing in its default color and then abruptly switching to the color of the first frame of the animation once it starts.

Pages: 1, 2, 3, 4

Next Pagearrow