Animating Bezier Curves

The other day I got the notion in my head that I wanted to draw some bezier curves in an animated fashion. I’m sure this has been done a million times before, but sometimes reinventing the wheel can be a good learning experience, so I turned to my good friend Wikipedia for some quick explanation. When you go to the Wikipedia entry for Bezier Curve, you see close to the top of the page that the formula for a quadratic b curve looks like this:

Seems kinda cryptic at first glance, but it’s pretty simple when broken down. P0 is our starting point, P1 is our control point, P2 is our end point and t is time. Written in actionscript then, we can get the x and y positions of our curve with the following couple lines:

var xpos:Number = ( (1 - time) * (1 - time)) * startPoint.x + 2 * (1 - time) * time * controlPoint.x + (time * time) * endPoint.x;
var ypos:Number = ( (1 - time) * (1 - time)) * startPoint.y + 2 * (1 - time) * time * controlPoint.y + (time * time) * endPoint.y;

You can see at the end of the formula that time (t) is a number that progresses from 0 to 1. Now in Flash/Actionscript terms, whenever you think of a numeric property changing its value over time, the word “tween” is the first thing that should pop into your head. My two (at least at the moment) favorite tweening engines are the Greensock TweenLite/TweenMax and the libspark BetweenAS3 engine. Both have their advantages and drawbacks. My general rule of thumb (for no real reason) is that I use TweenLite with Flashplayer 9 projects and BetweenAS3 for flashplayer 10. So for that reason, for the quick demo below, I went with BetweenAS3 (Note: if you’ve never used it before, you can check out the intro article I wrote over on TechLabs). Generally speaking all we need to do is create a start point, a control point, an end point, tween a time property from 0 to 1 and on every update use the 2 lines of script above to plot our curve.

As a quick aside, BetweenAS3 is able to handle both AS3 style events and old AS2 style callback functions. Personally speaking, I prefer using events over callbacks whenever possible, however callbacks tend to be quicker and less expensive. So another general rule of thumb: when dealing with data events or just general projects, tend to favor the AS3 Event structure – it will keep your code cleaner, it’s more object oriented, and it aids decoupling. When dealing with animation, games or other things where time and memory of the essence (e.g. mobile devices) go with callbacks as I did below.

Here then is a very quick animated Bezier Curve example:

package  {
 
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.geom.Point;
	import org.libspark.betweenas3.BetweenAS3;
	import org.libspark.betweenas3.easing.Quad;
	import org.libspark.betweenas3.tweens.ITween;
 
	/**
	 * Quick test of animated Bezier Curve
	 * @author Devon O.
	 */
 
	[SWF(width='500', height='300', backgroundColor='#CCCCCC', frameRate='60')]
	public class CurveTest extends Sprite {
 
		// Keep this public (or add accessor methods) to make accessible to tweening engine
		public var time:Number;
 
		private var _tween:ITween;
 
		// our 3 points
		private var _startPoint:Point;
		private var _controlPoint:Point;
		private var _endPoint:Point;
 
		public function CurveTest() {
			if (stage) init();
			else addEventListener(Event.ADDED_TO_STAGE, init);
		}
 
		private function init(event:Event = null):void {
			// start at the left edge two thirds of the way down
			_startPoint = new Point(0, stage.stageHeight * .66);
 
			// curve to the top center of the stage
			_controlPoint = new Point(stage.stageWidth * .5, 0);
 
			// and end on the right side two thirds down
			_endPoint = new Point(stage.stageWidth, stage.stageHeight * .66);
 
			// draw the curve when you click
			stage.addEventListener(MouseEvent.CLICK, clickHandler);
		}
 
		private function clickHandler(event:MouseEvent):void {
			// reset everything
			if (_tween != null && _tween.isPlaying) _tween.stop();
			graphics.clear();
			graphics.moveTo(_startPoint.x, _startPoint.y);
			graphics.lineStyle(2);
			time = 0;
 
			animateCurve();
		}
 
		private function animateCurve():void {
			// our tween to get time to go from 0 to 1 in 3 seconds
			_tween = BetweenAS3.tween(this, { time:1 }, null, 3.0, Quad.easeInOut);
			// using an anonymouse callback rather than event for speed
			_tween.onUpdate = drawCurve;
			_tween.play();
		}
 
		private function drawCurve():void {
			var xpos:Number = ( (1 - time) * (1 - time)) * _startPoint.x + 2 * (1 - time) * time * _controlPoint.x + (time * time) * _endPoint.x;
			var ypos:Number = ( (1 - time) * (1 - time)) * _startPoint.y + 2 * (1 - time) * time * _controlPoint.y + (time * time) * _endPoint.y;
 
			graphics.lineTo(xpos, ypos);
		}
	}
}

And that will give you this (click on the .swf’s stage to see it in action):

Get Adobe Flash player

And there you have a simple animated Bezier Curve.

So what would you use it for? Well, I’m sure you can think of any number of uses (plotting a line between two points on a map always looks nice when animated and curvy).

The whole reason I started digging into this though was because of a tweet from @mrdoob linking to an explanation of the classic Moppi Flower effect and I wanted to do something similar. And so, using the simple math above came up with the item below.

Get Adobe Flash player

Rockin good fun…

11 Comments »

  1. Lawrie says:

    Great article. Animating beziers are always nice, your flower effect at the bottom of the post especially so.

  2. Willie says:

    mighty fine

  3. Pedram says:

    wow,
    that’s very sweet.

  4. Og2t says:

    Great! I’ve just needed this today :)

  5. Devon O. says:

    Cool, Tomek! Glad something here could help…

  6. The equation was just what I needed. Thanks!

  7. leo says:

    This is great and works perfect! How would I move the line over a percentage instead of time?

    Let’s say I want this effect for a preloader in which the line is animated over percentage loaded instead of time?

  8. Devon O. says:

    Hey Leo,

    Thanks for the comment.

    Since time ranges from 0 to 1 in the equation, you could just swap that out with percent loaded (again ranging from 0 to 1). That should work fine as a preloader effect.

  9. Ninja says:

    Hello Devon,

    Just wanted to take a minute and say thank you for posting this. I’m working on a little android project and was looking for a way to implement moving along a curve – this was the guide that really helped my understanding. I was able to implement and it and it looks really cool =)

    Thanks again

RSS feed for comments on this post. / TrackBack URI

Leave a Reply

Devon O. Wolfgang

Technical Reviewer of “The Essential Guide to Flash CS4 AIR Development”

Contributing Author of “Flash AS3 for Interactive Agencies”

Senior Software Engineer at Meez

Starling Particle Editor

boids

Animated Particles, Books, and Code – It’s a New Year


It’s a new year[...]

bug

Logical Or Assignment Bug in ASC2


So, here’s something to keep an eye on if switching to AIR 3.8[...]

Starling Filter Collection

Starling Filter Collection


Building up a collection of filters for the Starling framework[...]

Starling Warp

Warp Filter for Starling


Another filter for the Starling framework[...]

promise

Promises Promises


What it boils down to is handling asynchronous tasks [...] in a clean, intelligent fashion [...]

GodRays

Starling ‘God Ray’ Filter


While cruising the internet today looking for interesting things to try out I ran across this fun little GPU Gem[...]

Alpha in Starling Filters and Basic Branching in AGAL


In plain English to create a circular mask we would want to do something like this[...]

Starling, Nape Physics, and PhysicsEditor


A look at using the PhysicsEditor tool for Nape and Starling [...]

Playing With a Couple Game Ideas


Just a couple game fragments, really[...]

One More Filter For Starling


Another filter for the Starling framework[...]

Filters in Starling


Using and writing filters in the Starling framework[...]

Towards a Better Scratch


Perhaps it was too much Meat Beat Manifesto in the late 80′s [...]

Learning AGAL with AGALMacroAssembler and OpenGL Examples

So the other day I sat down and thought to myself: self, it’s high time you learn you some of this new fancy pants AGAL[...]

UV Scrolling in Starling


Obviously this could come in pretty darned handy for space games, side scrollers, etc, etc[...]

Drawing on Stuff in Away3D 4.0

So, Easter Day, I thought I’d sit down and make a little ‘Paint on an Egg and Send it to Your Friend’ app.

Santabot: A Unity3D Flash Game


All right, so a Christmas game like “Santabot vs. The Flying Saucers from Mars” may be a day late[...]