Lately, I was asked to produce a flash animation for which I was given free initiative. As usual, I started coding in old fashion AS2, using MX tweens for the first time. I was pleased with the result but it appeared slightly slow, and it sometimes lost synchronization with the music – not that it was really ment to be in rythm though.
Anyway, I ended up with the decision to use AS3 instead, supposedly faster, and most of all, I discovered the Greensock Animation Platform, also known as GSAP – currently in V12. This API not only manages animation tweens in the simplest way, it also deals with your timeline sequences with ease.
I’ll just show sample code used in various sequences – you can watch a demo of the whole animation here
For example, this is how I animate the clouds back and forth :
1 2 3 4 5 6 7 8 9 |
var masterTimeline:TimelineLite = new TimelineLite(); var nuageTimeline:TimelineLite = new TimelineLite(); nuageTimeline.appendMultiple([ TweenMax.fromTo(nuage1, 50, {x:-114}, { x: 800, yoyo:true, repeat: -1, ease:Linear.easeNone } ), TweenMax.fromTo(nuage2, 40, {x:-102}, { x: 800, yoyo:true, repeat: -1, ease:Linear.easeNone, delay:10 } ), TweenMax.fromTo(nuage3, 60, {x:800}, { x: -168, yoyo:true, repeat: -1, ease:Linear.easeNone } ) ]); masterTimeline.append(nuageTimeline); |
masterTimeline
is the main holder where I’ll place all the sequences in the animation. It’s quite convenient as I can simply replay the whole animation calling masterTimeline.restart()
, nice and easy, don’t you think ?
nuageTimeline
is another timeline nested in the main timeline. It contains the tweens for each of the 3 clouds. You’ll notice they’re instances of TweenMax
, which has greater options than TweenLite
, like repeat
and yoyo
for example. I won’t detail all these parameters, GreenSock provides great documentation.
An other example is the first sequence, where the Barong head flies around before it hides behind the temple
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
masterTimeline.addLabel("start", 1); masterTimeline.addLabel("startbarong", 5); masterTimeline.insert(TweenLite.fromTo(scene, 4,{x:-1750, y:-1100, scaleX:4, scaleY:4}, {x:0, y:0, scaleX:1, scaleY:1, ease: Linear.easeInOut}), "start"); var barongteterot1:TimelineLite = new TimelineLite(); barongteterot1.append(new TweenLite(barong, 0.8, {rotation:-30, ease: Linear.easeOut})); barongteterot1.append(new TweenLite(barong, 0.8, {rotation:0, ease: Linear.easeOut})); barongTimeline.appendMultiple([ new TweenLite(barong, 1.6, {x:-30, y:145, ease: Quad.easeInOut}), new TweenLite(barong, 1.6, {scaleX:0.6, scaleY:0.6, ease: Linear.easeOut}), barongteterot1]); var barongteterot2:TimelineLite = new TimelineLite(); barongteterot2.append(new TweenLite(barong, 0.8, {rotation:30, ease: Linear.easeOut})); barongteterot2.append(new TweenLite(barong, 0.8, {rotation:0, ease: Linear.easeOut})); barongTimeline.appendMultiple([ new TweenLite(barong, 1.6, {x:470, y:125, ease: Quad.easeInOut, onComplete:swapDepth, onCompleteParams:[0]}), new TweenLite(barong, 1.6, {scaleX:0.2, scaleY:0.2, ease: Linear.easeOut}), barongteterot2]); var barongteterot3:TimelineLite = new TimelineLite(); barongteterot3.append(new TweenLite(barong, 0.4, {rotation:-30, ease: Linear.easeOut})); barongteterot3.append(new TweenLite(barong, 0.4, {rotation:0, ease: Linear.easeOut})); barongTimeline.appendMultiple([ new TweenLite(barong, 0.8, {x:250, y:255, ease: Expo.easeIn}), new TweenLite(barong, 0.8, {scaleX:0.05, scaleY:0.05, ease: Linear.easeOut}), barongteterot3]); masterTimeline.insert(barongTimeline,"startbarong"); |
The Api allows to define labels, as I did in the first 2 lines above, label “start” is 1 second in my main timeline, for instance.
The sequence starts with the scene zooming out from a close up on the character’s face. This Tween is inserted at label “start” in my timeline. I think good practice would be to define all the labels in the code just before setting the tweens in the animation, so you can have them all in one place if you need to adjust later on.
Afterwards, I set a sequence of 3 series of tweens, each nested in an individual timeline, nested in turn in a global timeline intended for the barong character, which is finally included to the main timeline. Notice how I can add multiple tweens at the same time with the appendMultiple()
method. This sequence makes the character fly to the left, then back to the right and finally dive, as it shrinks to a tiny size at the same stime. The rotation tweens make it bend its head as it moves from one side to the other.
This sequence is placed at label “startbarong” which is 5 seconds in the animation, so it will run just after the scene zooms out during 4 seconds.
Here’s one last example of animation management :
There are 40 flowers to animate from the center of the screen like some kind of explosion or erruption. Final positions, rotations and scales are known, we just need to give the animation a slight chaotic feel by not synchronizing this set of tweens.
The array fleurs
is initialized somewhere in the beginning of the code. As the flowers are all placed on the scene in their final position, we just need to store the attributes for x y scalex scaley & rotation
. The flower movieclips are named “fran1”, “fran2″… etc
1 2 3 4 5 6 7 8 9 10 11 |
for (i=1;i<=nbfleurs;i++) { var fparam:Object = new Object; fparam.mc=root["fran"+i]; fparam.x0=root["fran"+i].x; fparam.y0=root["fran"+i].y; fparam.xs0=root["fran"+i].scaleX; fparam.ys0=root["fran"+i].scaleY; fparam.rot=root["fran"+i].rotation; fleurs.push(fparam); } |
A simple loop inserts the tweens in the mastertimeline at label “startexplode” with random durations ranging from 2 to 3 seconds :
1 2 3 4 5 6 7 |
for (i=0;i<nbfleurs;i++) { dt = 2+Math.floor(Math.random()*20)/20; masterTimeline.insert(TweenLite.fromTo(fleurs[i].mc, dt, {x:400, y:500, scaleX:0, scaleY:0, alpha:1}, {x:fleurs[i].x0, y:fleurs[i].y0, scaleX:fleurs[i].xs0, scaleY:fleurs[i].ys0, rotation:fleurs[i].rot, ease:Bounce.easeOut}), "startexplode"); } |
As I’m writting this post, I learnt the TweenLite class was implemented with new methods in the current V12 of GSAP, such as to()
and add()
which are supposed to be replacing all the insert(), append(), insertMultiple(), appendMultiple()
methods. I guess it will make coding even more intuitive as well as reduce code size, so I must give it a try in the future.
Well, I haven’t finished with the GreenSock API, as they also provide the awsome LoaderMax which I’ll also try and probably show you rather sooner than later.
But the most appealing and most promising, in my opinion, is their JavaScript Animation Platform, which I definitely need to try as soon as I can spare some time !