I am very interested in learning a technique that has become very popular
lately in director interfaces, that which the button sprites can be grabbed
and "slung" across the stage etc. and then come to a graceful stop as
seen on the http://www.whereishere.com site produced by the makela's.
Any help or pointers would be greatly appreciated....
Let me start this discussion by saying that none of what I'm going to
write about here has any basis in the laws of physics. There are many
programmers out there who have done amazing programs using physics as
the basis for their algoritms, but I'm not one of them.
First, let's look at what Director provides for this effect, using standard
Score animation techniques. In this first demo movie, I have animated
a sprite (one of D7's new vector images) sliding across the stage over
a period of 30 frames. In the top example, note the yellow line with dots.
That's showing you the locH of the sprite in each subsequent frame, moving
left to right. Notice that they are evenly spaced. That means that the
speed of the sprite will remain constant throughout it's journey across
the stage.
In the lower example, I used Director's Tweening options, so you'll
notice that the yellow dots are not equidistant. Rather, they start out
far apart and get closer together at the end (right side). This means
that at the beginning of the path, the sprite is moving further per frame
than at the end, when it creeps only a few pixels per frame. This will
give it the effect of "slowing to a stop." To achieve this effect, open
the Tweening dialog box for the sprite. I selected the option to tween
the path, set the Curvature all the way to Extreme (for maximum effect),
selected Smooth Changes, and set "Ease-Out" to 100%.
This score based solution will work in many situations, but in other
cases, you'll want to achieve the same effect without being tied to the
score. For this, we'll need to create a behavior. Let's make a list of
the things we'd want to be able to set as parameters when we're authoring.
Starting point (locH and locV)
Ending point (locH and locV)
Number of frames for the move
Number of frames to "Ease In"
Number of frames to "Ease Out"
The EaseIn and EaseOut numbers essentially give you the same control
you'd have using the Curvature slider in Director's Tween Options. They
allow you to designate how fast your sprite will accelerate and decelerate.
The lower the number, the more sudden the acceleration or deceleration.
This is what our dialog box should look like when we drop the behavior
on a sprite. Here's the code for declaring the properties and setting
up the getPropertiesDescriptionList.
Notice that I'm assuming the startH and startV of the sprite will be
the current locH & locV of the sprite at the time the behavior is applied.
Also, I default the endH and endV to the same points, so it'll be easy
in many cases to figure out what to input for this number. For example,
for a straight horizontal motion, you'll leave the endV at the default
(same as the startV). And, you may know that you want the sprite to move
300 pixels, for example, so you can simply add 300 to whatever number
appears as a default. The last thing to note is a property called pFlag.
This is simply the "switch" that will be responsible for starting the
motion. I initialize that property in the beginSprite handler that follows.
Before we get into the code, we need to cover the concepts and some
math. In order to get a geometrically smooth acceleration and deceleration,
I decided to use the smooth curves of a sine wave -- at least a portion
of the sine wave cycle. If you think about how we'd describe the smooth
acceleration that we want, you could graph it like this:
In this illustration, you can see that the red segment of the sine wave
represents the way that we want to "ramp up" the speed of the sprite --
easing it into motion. Note that it is a more gradual slope as the motion
begins, and then smoothly comes out of the acceleration as well. The green
segment represents Easing Out of the motion, again with gradual transitions
at the beginning and end of the deceleration. Attempting to simulate this
sort of motion is complicated, but the results will be smooth as silk.
In this example, I'm only moving horizontally and I've turned trails
ink on so that you can compare the motion of the various sprites. Note
that the dots are closer together as the sprites easeIn and easeOut of
motion. Download this *.dir file and look at the Tween Behavior. (Mac
or PC)
In our beginSprite handler, we'll start by determining the total number
of pixels to be moved (both horizontal and vertical). I call these values
deltaH and deltaV, and they're evaluated by simply subtracting the starting
H & V from the ending H & V. Next, I want to find out how many (if any)
midFrames I have. I'm using the term midFrames to describe frame represented
by the flat black line in the diagram above -- the frames that are neither
easeIn or easeOut frames. This is simple to calculate: midFrames = total
frames - easeIn frames - easeOut frames. I added a simple if statement
to assure that the number of easeIn and easeOut frames doesn't exceed
our total frames for the motion.
Now comes the complicated part. We have to figure out how many pixels
per frame the sprite will be moving during the midFrames. If the motion
is linear, with no easeIn or easeOut, then it's simply the total number
of pixels divided by the total frames. The problem is that easeIn and
easeOut -- by definition -- change that formula. For example, let's compare
the first ten frames of two different animations. Example A moves steadily,
a distance of 100 pixels, over a period of 20 frames. It's easy to see
that -- with steady motion -- the sprite moves 5 pixels per frame. Now
consider example B, which also moves a total of 100 pixels in 20 frames,
but eases into that motion. If it's going slower (moving fewer than 5
pixels/frame) at the beginning in order to ease into the motion, then,
it will obviously need to move MORE than 5 pixels/frame during the last
10 frames to make it to the destination in time. So, after the first 10
frames of example B, how far will the sprite have moved? Something less
than 50, but what?
Since the motion wil be defined by a sine wave, I thought that there
might be a constant which represents the portion of the motion that we
could expect it to have moved. In fact, it's not a constant, but it's
always pretty darned close to .65. It varies based on the number of frames
for the easeIn or easeOut. Therefore, in the behavior, I set it up to
calculate this "inFactor" and "outFactor" dynamically, based on the number
of frames for each. Once they're calculated, I can figure out the average
number of pixels per frame that the sprite will need to move (horizontally
and vertically).
Once I know the average number of pixels per frame, I can build a list
of points which represent the H & V change for each frame in the animation.
This is done in the buildPointList handler. I'm not going to explain this
process (or the math for calculating the easeIn and easeOut points). I
figure that if you're into the math, you'll understand what I've done,
and if you're not, I won't waste your time.
Ultimately, we end up with a list of points in which each item describes
the amount of horizontal and vertical change for the next frame. When
the sprite's motion is activated with a mouseUp, a flag changes to #move,
and then the exitFrame handler simply resets the sprite's loc and deletes
that item from the list. When the list is empty, the move is over and
the flag is reset to #stop. Easy, right?
Good luck with your project, and let me know what sort of fascinating
variations you make with this. You should also read the excellent
work that Darrel Plant has done with Bezier curves.
Patrick McClellan is Director Online's co-founder. Pat is Vice President, Managing Director for Jack Morton Worldwide, a global experiential marketing company. He is responsible for the San Francisco office, which helps major technology clients to develop marketing communications programs to reach enterprise and consumer audiences.