Learning ActionScript 3.0: Chapter 7, Motion
Pages: 1, 2, 3, 4, 5, 6, 7, 8
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.
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.
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.
This excerpt is from Learning ActionScript 3.0. Learning ActionScript 3.0 gives you a solid foundation in the Flash language and demonstrates how you can use it for practical, everyday projects. The book does more than give you a handful of sample scripts, defining how ActionScript and Flash work. It gives you a clear look into essential topics such as logic, event handling, displaying content, migrating legacy projects to ActionScript 3.0, classes, and much more. Written for those new to the language, this book doesn't rely exclusively on prior knowledge of object-oriented programming (OOP). Instead, it helps you expand your skillset by first focusing on clear, concise examples in the timeline, evolving into OOP examples over time-allowing you to choose the programming approach with which you are most comfortable.
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 }
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.