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):
[kml_flashembed publishmethod=”static” fversion=”10.0.0″ movie=”http://blog.onebyonedesign.com/wp-content/uploads/2010/03/curve_example.swf” width=”500″ height=”300″ targetclass=”flashmovie”]
[/kml_flashembed]
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.
[kml_flashembed publishmethod=”static” fversion=”10.0.0″ movie=”http://blog.onebyonedesign.com/wp-content/uploads/2010/03/curves.swf” width=”700″ height=”400″ targetclass=”flashmovie”]
[/kml_flashembed]
Rockin good fun…
Post a comment