Archive

Archive for the ‘Animation’ Category

Grape Animation Library

September 2nd, 2009

logo

http://code.google.com/p/grape-as3/

Grape is the animation library I introduced last post. Its goal is to offer a modular means to animate along parametrized paths.

Here’s the updated demo:

Get Adobe Flash player

Architecture

Animations have 2 essential component parts: a path and a curve. Paths define position and curves define progression. Both paths and curves are stateless, meaning state is managed by the Animation type and the engine, Grape. This also means paths and curves are freely swappable without a need to clone, etc.

Grape’s Animation type by itself doesn’t assign values to your objects as you’re probably accustomed to with most popular tweening engines. Instead, it simply manages the state of the animation. Its state is a Vector of type Number. This allows the user to reference this state without necessarily tying it to a DisplayObject for instance. When you do want to bind the state of the animation to a DisplayObject, you’ll use a Binding, which simply applies the animation’s state to the appropriate object. The average user probably won’t ever touch a Binding directly, but it’s worth noting.

API

The engine is a singleton called Grape. It has creation methods for the 2 most likely animation scenarios, create2DAnimation and createPropertyAnimation. The latter should be fairly identical to how popular engines work. create2DAnimation will ideally be the typical use-case.

//create the path to animate along
var spiral:Path2D = new SpiralPath2D( new Point( 100, 100 ), 200, 0 );
 
//view is your DisplayObject and 2000 is the duration in milliseconds.
Grape.getInstance.create2DAnimation( view, spiral, 2000 );

And that’s it, your DisplayObject will tween in a spiral with original radius of 200 and end radius of 0 for 2 seconds. You can also set the start time (defaults to instantaneous start), the curve (defaults to linear), whether the animation loops (defaults to false), if the animation is to be played in reverse (defaults to false), and if the animation should reverse on loop (false).

The method returns the animation instance, in the case that you need a reference or would like to handle some of its events:

var anim:Animation = Grape.getInstance.create2DAnimation( view, spiral, 2000 );
 
//add listener for animation complete event
anim.addEventListener( Event.COMPLETE, onAnimationComplete );
 
function onAnimationComplete( event:Event ) : void
{
   //animation done!
}

You can also listen for an event everytime a looping animation loops and each tick of the engine:

//add listener for animation loop event
anim.addEventListener( Animation.LOOP, onAnimationLoop );
 
//listen for Grape's tick
Grape.getInstance().addEventListener( Grape.TICK, onGrapeTick );

Paths

LinearPath2D, CirclePath2D, SpiralPath2D, SineWavePath2D

These are all pretty self explanatory. Linear moves along a line segment. Circle moves around a circle’s edge; you can set the beginning and end radian. Spiral is the same as Circle but also interpolates radius. SineWavePath2D extends LinearPath2D, and so the wave deviates from the line segment.

ComplexPath2D

ComplexPath2D allows you to tween across multiple paths. You supply it a Vector of paths and a Vector of starting cues, specifically the percentage through the tween at which you want the corresponding path to begin.

//create the paths that will be added to the complex path
var spiral:Path2D = new SpiralPath2D( new Point( 100, 100 ), 200, 0 );
var linear1:LinearPath2D = new LinearPath2D( new Point( 100, 100 ), new Point( 200, 200 ) );
var linear2:LinearPath2D = new LinearPath2D( new Point( 200, 200 ), new Point( 200, 100 ) );
var linear3:LinearPath2D = new LinearPath2D( new Point( 200, 100 ), new Point( 100, 100 ) );
 
var paths:Vector.<Path> = Vector.<Path>( [ spiral, linear1, linear2, linear3  ] );
 
//spiral and linear1 will take 25% of the animation's duration, linear2 will take 10%
//and linear3 will take 40%
var cues:Vector.<Number> = Vector.<Number>( [ 0, 0.25, 0.5, 0.6 ] );
 
//create the complex path
var complex:ComplexPath2D = new ComplexPath2D( paths, cues );

Tweening along a twisty train track for example is something that just wouldn’t be possible with any other engine, and forget about trying to apply one cohesive interpolation across the whole path. Complex paths make these stupid easy. And because complex paths are paths, you can nest them inside of each other to create quickly compound, complex animations!

QuadraticBezierPath2D, CubicBezierPath2D

Quadratic Bezier curves are what you’re familiar with from Graphics. Cubic Beziers just offer one extra control point.

var bez:CubicBezierPath2D = new CubicBezierPath2D( new Point( 20, 20 ), new Point( 400, 200 ), new Point( 400, 600 ), new Point( 600, 600 ) );

Bezier’s take one other argument, the Boolean reparametrize. Beziers are like stapling saltwater taffy to the table and lifting it at the center. A really small bit of the curve in terms of its parametrization is left at the staples, while a lot is in your hand near the control points, even though the opposite may be true spatially. What does this mean? It means that even with a linear curve, it’s not likely you can keep constant velocity along the curve. So this Boolean flags whether to reparametrize the curve by arc length. This is a somewhat expensive process and so it defaults to false. Here’s an example of this, the black tween has been reparametrized, the red has not.

Get Adobe Flash player

LinearSplinePath2D, CosineSplinePath2D, HermiteSplinePath2D, CatmullRomSplinePath2D

Each of the splines takes a Number Vector (x,y pairs) and interpolates between them in their own special way. Linear connects each point linearly, Cosine steps over part of a wavelength to give a (OK, not too nice) curve through each point. Hermite also takes a vector of tangents to give the most amount of control. You can read about them on wikipedia. Catmull-Rom Splines are a subset of Hermite curves. They offer less control, but do not require the user to specify the tangents. Here’s an image of the different interpolations. Top to bottom it’s Linear, Cosine and Catmull-Rom:

splines

This is the code that created the image above:

var p1:Vector.<Number> = Vector.<Number>( [ 20, 20, 100, 100, 120, 50, 300, 300, 400, 50, 500, 200 ] );
var p2:Vector.<Number> = Vector.<Number>( [ 20, 120, 100, 200, 120, 150, 300, 400, 400, 150, 500, 300 ] );
var p3:Vector.<Number> = Vector.<Number>( [ 20, 220, 100, 300, 120, 250, 300, 500, 400, 250, 500, 400 ] );
 
var path:Path2D = new LinearSplinePath2D( p1 );
path.render( graphics );
path = new CosineSplinePath2D( p2 );
path.render( graphics );
path = new CatmullRomSplinePath2D( p3 );
path.render( graphics );

These have great applicability to dynamically generated paths and lots of other game-related functions.

PhysicsPath2D

This should maybe be called projectile instead of physics. You supply initial position, starting velocity and acceleration vectors and how many seconds the entire tween represents.

Debug Rendering

Each path is renderable as a helpful measure. Because of the way paths work, it was easy to handle all paths in one render method, keeping file size down. You can see the spline API above, just pass a graphics instance to draw into.

Alright, I’m excited to see what you make of this and what sorts of cool things you can make! It’s hosted on Google Code under the MIT license. I’ll try to get it commented soon enough, send me any bugs or feature requests.

http://code.google.com/p/grape-as3/

drew ActionScript 3.0, Animation, Flash Player 10

New Flash Animation Library

August 31st, 2009

What!? Why would I write another tweening engine? Because it’s awesome! It addresses some of the things that other libraries don’t. I realized that if I wasn’t just animating from here to there, or fading in, I’d end up having to write a custom solution. Even seemingly simple stuff like moving an object in a circle isn’t really doable.

So the solution is to break animations into 2 component parts: a path and a curve. The path represents the spatial component of the animation and the curve represents the temporal.

Currently there’s only a linear curve and a PennerCurve, which can have any Robert Penner-esque easing function assigned to it.

Paths:

  • CirclePath2D
  • ComplexPath2D
  • CubicBezierPath2D
  • LinearPath2D
  • Path1D
  • PhysicsPath2D
  • QuadraticBezierPath2D
  • SineWavePath2D
  • SpiralPath2D

The coolest thing here is the complex path which allows you to combine multiple paths into 1 animation. So the progression of the curve is applied across the whole of the complex path. And, because complex paths are paths themselves, they are nestable!

From the demo below (select ComplexPath2D 2), here’s the most verbose example, which combines 3 circle paths as 1 complex path and nests that inside another complex path containing a bezier and sine wave path:

 
//circle's go center point, radius, start radian, end radian
var c1:CirclePath2D = new CirclePath2D( new Point( 150, 200 ), 50, Math.PI * 2, 0 );
var c2:CirclePath2D = new CirclePath2D( new Point( 250, 200 ), 50, Math.PI, Math.PI * 3 );
var c3:CirclePath2D = new CirclePath2D( new Point( 300, 200 ), 100, Math.PI, Math.PI * 3 );
 
//the complex path takes the list of paths and a list of cue points
var complex:Path = new ComplexPath2D( Vector.<Path>( [ c1, c2, c3 ] ), Vector.<Number>( [ 0, 0.25, 0.5 ] ) );
 
//the bezier classes take the anchor and control points
var bez:CubicBezierPath2D = new CubicBezierPath2D( new Point( 200, 200 ), new Point( 350, 0 ), new Point( 350, 500 ), new Point( 350, 200 ) );
 
//sine wave takes a start and end point, frequency and amplitude
var sine:SineWavePath2D = new SineWavePath2D( new Point( 350, 200 ), new Point( 200, 200 ), 3, 50 );
 
var path:ComplexPath2D = new ComplexPath2D( Vector.<Path>( [ complex, bez, sine ] ), Vector<Number>( [ 0, 0.5, 0.75 ] ) );
 
//the runner binds the view to the animation
runner = new Runner2D( view, path, durationStepper.value, -1, getCurve(), loop.selected, reverse.selected );

Here’s the demo:

Get Adobe Flash player

I’ll be releasing it under the MIT license in a few days.

drew ActionScript 3.0, Animation