Category Archives: motion

Circle Fitting

Actionscript:
  1. var circs:Array = []
  2. var circNum:int = 600;
  3. addEventListener(Event.ENTER_FRAME, onAdd);
  4. function onAdd(evt:Event):void {
  5.     if (circs.length <circNum){
  6.         makeGrowable();
  7.     }
  8. }
  9.  
  10. function makeGrowable(){
  11.    
  12.     var s:MovieClip = MovieClip(addChild(new MovieClip()));
  13.     s.x = Math.random() * stage.stageWidth;
  14.     s.y = Math.random() * stage.stageHeight;
  15.     with(s.graphics){
  16.         lineStyle(0,0);
  17.         drawCircle(0,0,10);
  18.     }
  19.     s.scaleX = s.scaleY = 0;
  20.     circs.push(s);
  21.     s.addEventListener(Event.ENTER_FRAME, onScaleUp);
  22. }
  23.  
  24. function onScaleUp(evt:Event):void {
  25.     var c:MovieClip = MovieClip(evt.currentTarget);
  26.     c.scaleX = c.scaleY += 0.05;
  27.     for (var i:int = 0; i<circs.length; i++){
  28.         var circ:MovieClip = circs[i];
  29.         if (circ != c){
  30.             var amt:Number = circ.width/2 + c.width/2;
  31.             var dx:Number = circ.x - c.x;
  32.             var dy:Number = circ.y - c.y;
  33.             var dist:Number = Math.sqrt(dx * dx + dy * dy);
  34.             if (amt> dist){
  35.                 c.removeEventListener(Event.ENTER_FRAME, onScaleUp);
  36.                 if (c.scaleX <0.1){
  37.                     if (contains(c)){
  38.                     removeChild(c);
  39.                     }
  40.                 }
  41.             }
  42.         }
  43.        
  44.     }
  45. }

Circle fitting is one of those things I've never bothered to do... today I figured I'd give it a try and this is what I came up with. I posted it on wonderfl:

Also posted in Graphics, misc | Tagged , , , | 6 Comments

3D Ring

Actionscript:
  1. [SWF(width = 500, height=500)]
  2. var ring:MovieClip = createRing();
  3. ring.x = stage.stageWidth / 2;
  4. ring.y = stage.stageHeight / 2;
  5. addChild(ring);
  6.  
  7. function createRing(sectionNum:int = 30):MovieClip{
  8.     var container:MovieClip = new MovieClip();
  9.     container.circles = [];
  10.     container.theta = 0;
  11.     container.thetaDest = 0;
  12.     var step:Number = (Math.PI * 2) / sectionNum;
  13.     for (var i:int = 0; i<sectionNum; i++){
  14.         var c:MovieClip = new MovieClip();
  15.         with (c.graphics){
  16.             lineStyle(0,0x000000);
  17.             beginFill(0xCCCCCC);
  18.             drawCircle(0,0,20);
  19.         }
  20.         c.thetaOffset = step * i;
  21.         container.addChild(c);
  22.         container.circles.push(c);
  23.     }
  24.     container.addEventListener(Event.ENTER_FRAME, onRun);
  25.     return container;
  26. }
  27. function onRun(evt:Event):void {
  28.     var container:MovieClip = MovieClip(evt.currentTarget);
  29.     var num:int = container.circles.length;
  30.     for (var i:int = 0; i<num; i++){
  31.         var c:MovieClip = container.circles[i];
  32.         var angle:Number = container.theta + c.thetaOffset;
  33.         c.x = 200 * Math.cos(angle);
  34.         c.y = 100 * Math.sin(angle);
  35.         c.scaleX = (100 + c.y) / 120 + 0.2;
  36.         c.scaleY = c.scaleX;
  37.     }
  38.     container.circles.sortOn("y", Array.NUMERIC);
  39.     for (i = 0; i<num; i++){
  40.         container.addChild(container.circles[i]);
  41.     }
  42.     if (container.mouseX <-100){
  43.         container.thetaDest -= 0.05;
  44.     }
  45.     if (container.mouseX> 100){
  46.         container.thetaDest += 0.05;
  47.     }
  48.     container.theta += (container.thetaDest  - container.theta) / 12;
  49.    
  50. }

This snippet shows how to create a 3D ring navigation using sine and cosine. Have a look:

Also posted in 3D, Graphics, MovieClip, UI, arrays, sortOn | Tagged , , | 3 Comments

Propeller Sketch

Actionscript:
  1. makeFlyer();
  2.  
  3. function makeFlyer():void{
  4.     var thing:MovieClip = new MovieClip();
  5.     thing.x = 200;
  6.     thing.y = 200;
  7.    
  8.     addChild(thing);
  9.    
  10.     var prop:Shape = new Shape();
  11.     with (prop.graphics){
  12.         lineStyle(0,0x000000);
  13.         beginFill(0x000000);
  14.         moveTo(-100,0);
  15.         curveTo(-100, -30, 0, 0);
  16.         curveTo(100, 30, 100, 0);
  17.         curveTo(100, -30, 0, 0);
  18.         curveTo(-100, 30, -100, 0);
  19.     }
  20.     prop.scaleX = prop.scaleY = 0.5;
  21.     var container:MovieClip = new MovieClip();
  22.     //container.x = -50;
  23.     container.addChild(prop);
  24.     container.scaleY = 0.6;
  25.     thing.addChild(container);
  26.    
  27.     var body:Shape = new Shape();
  28.     with (body.graphics){
  29.         lineStyle(0, 0x000000);
  30.         beginFill(0x000000);
  31.         lineTo(0,80);
  32.         drawCircle(0,80,10);
  33.     }
  34.     thing.addChild(body);
  35.     thing.velX = 0;
  36.     thing.velY = 0;
  37.     thing.posX = thing.x;
  38.     thing.posY = thing.y;
  39.     thing.theta = 0;
  40.     thing.prop = prop;
  41.     thing.addEventListener(Event.ENTER_FRAME, onRun);
  42. }
  43. function onRun(evt:Event):void{
  44.     var t:MovieClip = MovieClip(evt.currentTarget);
  45.     t.prop.rotation += 10
  46.     t.velY = 3 * Math.cos(t.theta);
  47.     t.velX = 3 * Math.sin(t.theta / 2);
  48.     t.theta += 0.05
  49.     t.posX += t.velX;
  50.     t.posY += t.velY;
  51.    
  52.     t.x = t.posX;
  53.     t.y = t.posY;
  54. }

This snippet creates a small flying object that moves with sine and cosine.


Have a look at the swf...

Posted in motion | Tagged , , | 2 Comments

Circle Mouse Toy

Actionscript:
  1. var circles:Array = [];
  2. for (var i:int = 0; i<30; i++){
  3.     var c:Sprite = makeCircle();
  4.     c.x = stage.stageWidth / 2;
  5.     c.y = stage.stageHeight / 2;
  6.     c.scaleX = 1 + i/2;
  7.     c.scaleY = 0.5 + i/4;
  8.     addChild(c);
  9.     circles.push(c);
  10. }
  11. addEventListener(Event.ENTER_FRAME, onLoop);
  12. function onLoop(evt:Event):void {
  13.     circles[0].y += (mouseY - circles[0].y) / 4;
  14.     for (var i:int = 1; i<circles.length; i++){
  15.         var pre:Sprite = circles[i - 1];
  16.         circles[i].y += (pre.y - circles[i].y) / 4;
  17.     }
  18. }
  19. function makeCircle():Sprite{
  20.     var s:Sprite = new Sprite();
  21.     with(s.graphics){
  22.         lineStyle(0,0x000000);
  23.         drawCircle(0,0,10);
  24.     }
  25.     return s;
  26. }

This morning I woke up with a vision of this simple mouse toy in my head. I decided I might as well code it up... I may do more simple things like this in the next few days, it's relaxing.

Also posted in Graphics, misc | Tagged , , | 5 Comments

Nonsense Clocks

Actionscript:
  1. [SWF(width = 500, height=500, backgroundColor=0x000000)]
  2.  
  3. var clockNum:int = 100;
  4. var clocks:Vector.<Function> = new Vector.<Function>(clockNum, true);
  5.  
  6. var clockContainer:Sprite = Sprite(addChild(new Sprite()));
  7. clockContainer.x = stage.stageWidth / 2;
  8. clockContainer.y = stage.stageHeight / 2;
  9. buildClocks();
  10. runClocks();
  11.  
  12. function buildClocks():void{
  13.     for (var i:int = 0; i<clockNum; i++){
  14.         var theta:Number = Math.random() * Math.PI * 2;
  15.         var radius:Number = Math.random() * 200;
  16.         var xp:Number = radius * Math.cos(theta);
  17.         var yp:Number = radius * Math.sin(theta);
  18.         clocks[i] = makeClock(xp,yp,Math.random() * Math.PI * 2);
  19.     }
  20. }
  21. function runClocks():void{
  22.     addEventListener(Event.ENTER_FRAME, onRunClocks);
  23. }
  24. function onRunClocks(evt:Event):void{
  25.     for (var i:int = 0; i<clockNum; i++){
  26.         clocks[i]();
  27.     }
  28.     clockContainer.rotationX = clockContainer.mouseY / 30;
  29.     clockContainer.rotationY = -clockContainer.mouseX / 30;
  30. }
  31. function makeClock(x:Number, y:Number, time:Number=0):Function{
  32.     var radius:Number = Math.random() * 20 + 5;
  33.     var border:Number = radius * 0.2;
  34.     var smallRadius:Number = radius - radius * 0.3;
  35.    
  36.     var clock:Sprite = Sprite(clockContainer.addChild(new Sprite()));
  37.     clock.x = x;
  38.     clock.y = y;
  39.     clock.z = 100 - Math.random() * 200;
  40.     clock.rotationX = Math.random() * 40 - 20;
  41.     clock.rotationY = Math.random() * 40 - 20;
  42.     clock.rotationZ = Math.random() * 360;
  43.     return function():void{
  44.         with (clock.graphics){
  45.             clear();
  46.             lineStyle(1,0xFFFFFF);
  47.             drawCircle(0,0,radius + border);
  48.             var xp:Number = smallRadius * Math.cos(time/2);
  49.             var yp:Number = smallRadius * Math.sin(time/2);
  50.             moveTo(0,0);
  51.             lineTo(xp, yp);
  52.             xp = radius * Math.cos(time);
  53.             yp = radius * Math.sin(time);
  54.             moveTo(0,0);
  55.             lineTo(xp, yp);
  56.         }
  57.         time+=0.1;
  58.     }
  59. }


You can go check the swf out at wonderfl.net...

Also posted in 3D, Graphics, misc | Tagged , , | 3 Comments

Rotation Property Weirdness

Actionscript:
  1. var boxA:Shape = Shape(addChild(new Shape()));
  2. with (boxA.graphics) beginFill(0), drawRect(-10,-10,20,20);
  3.  
  4. var boxB:Shape = Shape(addChild(new Shape()));
  5. with (boxB.graphics) beginFill(0), drawRect(-10,-10,20,20);
  6.  
  7. boxA.x = 100;
  8. boxA.y = 100;
  9.  
  10. boxB.x = 200;
  11. boxB.y = 100;
  12.  
  13. var rot:Number = 32750;
  14.  
  15. addEventListener(Event.ENTER_FRAME, onLoop);
  16. function onLoop(evt:Event):void {
  17.   rot += 1
  18.   // will stop rotating
  19.   boxA.rotation = rot
  20.   // will keep rotating
  21.   boxB.rotation = rot % 360;
  22. }

I recently became aware of a strange aspect of the rotation property on DisplayObjects. For some reason, once it's value goes a little beyond ~32750 the DisplayObject will simply stop rotating. If you read the rotation property it is still changing, but there is no visual update - a quick check on the DisplayObject.transform.matrix property will show that the value has stopped.

The easy fix is to use mod before applying the value to the rotation property. Surprised I've never come across this one before. Maybe someone can shed some light on this.


// for people searching google for solutions to this problem I'll add the following key words:
MovieClip stops rotating, DisplayObject stops rotating, rotation property broken, not rotating

Also posted in DisplayObject, misc | Tagged , , | 1 Comment

Fp10 3d Logo

Actionscript:
  1. var container:Sprite = new Sprite();
  2. container.x = stage.stageWidth / 2;
  3. container.y = stage.stageHeight / 2;
  4. addChild(container);
  5.  
  6. var redBox:Sprite = new Sprite();
  7. redBox.graphics.beginFill(0xFF0000);
  8. redBox.graphics.drawRect(-50,-250,100,500);
  9. redBox.rotationZ = 10;
  10. container.addChild(redBox);
  11.  
  12. var logos:Array = []
  13. var elements:Array = [];
  14. elements.push({element:redBox, z:0});
  15.  
  16. // add the logos
  17. for (var i:int = 0; i<6; i++){
  18.     var logoContainer:MovieClip = new MovieClip();
  19.     var logoText:TextField = new TextField();
  20.     logoText.defaultTextFormat = new TextFormat("_sans", 50);
  21.     logoText.text = "LOGO";
  22.     logoText.autoSize = "left";
  23.     logoText.selectable= false;
  24.    
  25.     logoText.x = -logoText.width / 2;
  26.     logoText.y = -logoText.height / 2;
  27.     logoContainer.addChild(logoText);
  28.     logoText.backgroundColor = 0xFFFFFF;
  29.    
  30.     container.addChild(logoContainer);
  31.     logos.push(logoContainer);
  32.     elements.push({element:logoContainer, z:0});
  33. }
  34.  
  35. var ang:Number = -Math.PI / 2;
  36. var rotationSpeed:Number = 0.05;
  37. addEventListener(Event.ENTER_FRAME, onLoop);
  38. function onLoop(evt:Event):void {
  39.    
  40.      var dx:Number = (mouseY - stage.stageHeight / 2) / 10;
  41.      var dy:Number = (mouseX - stage.stageWidth / 2) / 10;
  42.      container.rotationX += (dx - container.rotationX) / 4;
  43.      container.rotationY += (dy - container.rotationY) / 4;
  44.      
  45.      ang += rotationSpeed;
  46.      for (var i:int = 0; i<logos.length; i++){
  47.          var logo:Sprite = logos[i];
  48.          logo.x = 150 * Math.cos(ang + i);
  49.          logo.z = 150 * Math.sin(ang + i);
  50.          logo.alpha = 1 - logo.z / 200;
  51.          logo.rotationY = -Math.atan2(logo.z, logo.x)  / Math.PI * 180  - 90;
  52.      }
  53.      
  54.      // z-sort
  55.      for (i = 0; i<elements.length; i++){
  56.           elements[i].z = elements[i].element.transform.getRelativeMatrix3D(this).position.z;
  57.      }
  58.      
  59.     elements.sortOn("z", Array.NUMERIC | Array.DESCENDING);
  60.     for (i = 0; i<elements.length; i++) {
  61.         container.addChild(elements[i].element);
  62.     }
  63. }

A student of mine was having trouble creating a 3D logo for a client. I created this snippet to help explain how some of the fp10 3D stuff works.... z-sorting etc... The code could be optimized a bit... but it works nicely...


Have a look at the swf...

Also posted in 3D, misc | Tagged , , , | 2 Comments

Bounce Ball Inside a Circle

Actionscript:
  1. package  {
  2.     import flash.display.Shape;
  3.     import flash.display.Sprite;
  4.     import flash.geom.Point;
  5.  
  6.     /**
  7.      * Re: http://board.flashkit.com/board/showthread.php?t=797453
  8.      * @author makc
  9.      * @license WTFPLv2
  10.      */
  11.     public class BouncingBall extends Sprite{
  12.         public function BouncingBall () {
  13.             r = 10;
  14.             ball = new Shape;
  15.             ball.graphics.beginFill (0);
  16.             ball.graphics.drawCircle (0, 0, r);
  17.             addChild (ball);
  18.             v = new Point;
  19.             v.x = Math.random ();
  20.             v.y = Math.random ();
  21.             V = 1 + 20 * Math.random ();
  22.             v.normalize (V);
  23.             R = 200; X = 465 / 2; Y = 465 / 2;
  24.             graphics.lineStyle (0);
  25.             graphics.drawCircle (X, Y, R);
  26.             ball.x = X + 100;
  27.             ball.y = Y - 100;
  28.             addEventListener ("enterFrame", loop);
  29.         }
  30.         private var r:Number;
  31.         private var ball:Shape;
  32.         private var v:Point;
  33.         private var V:Number;
  34.         private var R:Number;
  35.         private var X:Number;
  36.         private var Y:Number;
  37.         private function loop (e:*):void {
  38.             ball.x += v.x;
  39.             ball.y += v.y;
  40.             // R-r vector
  41.             var P:Point = new Point (X - ball.x, Y - ball.y);
  42.             if (P.length> Math.sqrt ((R - r) * (R - r))) {
  43.                 // normalize R-r vector
  44.                 P.normalize (1);
  45.                 // project v onto it
  46.                 var vp:Number = v.x * P.x + v.y * P.y;
  47.                 // subtract projection
  48.                 v.x -= 2 * vp * P.x;
  49.                 v.y -= 2 * vp * P.y;
  50.                 v.normalize (V);
  51.                 // move away from bounding circle
  52.                 P = new Point (X - ball.x, Y - ball.y);
  53.                 while (P.length> Math.sqrt ((R - r) * (R - r))) {
  54.                     ball.x += v.x;
  55.                     ball.y += v.y;
  56.                     P = new Point (X - ball.x, Y - ball.y);
  57.                 }
  58.             }
  59.         }
  60.     }
  61. }

Makc3d said I could choose one of his excellent wonderfl.net pieces and submit it to the contest. This snippet creates a ball that bounces off the inside of a circle. I thought this was a pretty unique way to go about doing this - and found it easy to add gravity and other cool features to it.

Have a look at the swf over at wonderfl....

Some Makc3d links:
>> http://makc3d.wordpress.com/
>>http://code.google.com/p/makc/
>> http://wonderfl.net/user/makc3d

Makc3d elaborated on his code a bit via e-mail. He said that his technique sacrifices accuracy for simplicity... and that if you simplify too much it would be easy to break the code. "e.g. comment out piece of code where it says "move away from bounding circle""...

Here is a picture that Makc3d drew explaining why you need to multiply by 2:

Posted in motion | Tagged , , , | Comments closed

QuickBox2D 1.1 (2 major bug fixes)

Since the release of QuickBox2D 1.0 two bugs were discovered by numerous developers. The first bug was the inability to properly destroy group objects. The second bug was a small memory leak that caused most QuickObjects to remain in memory. Both of these bugs are now resolved.

Download QuickBox2D 1.1

Testing the memory leak. In QuickBox2D 1.0 if you created and destroyed 100s of rigid bodies, the ram would very slowly rise... Sometimes it would get garbage collected, but the memory would never fully be released. I created a simple test to make sure this is fixed in 1.1:

Actionscript:
  1. import com.actionsnippet.qbox.*;
  2.  
  3. var sim:QuickBox2D = new QuickBox2D(this, {debug:false});
  4.  
  5. sim.createStageWalls();
  6.  
  7. var levelParts:Array = [];
  8. const TWO_PI:Number = Math.PI * 2;
  9.  
  10. // destroys and then creates a bunch of rigid bodies
  11. // called every second
  12. buildRandomLevel();
  13. setInterval(buildRandomLevel, 1000);
  14.  
  15. var txt:TextField = TextField(addChild(new TextField()));
  16. txt.x = txt.y = 30;
  17. txt.backgroundColor = 0xFFFFFF;
  18. sim.start();
  19.  
  20. // display amount of ram used, to make sure garbage collection is working
  21. sim.addEventListener(QuickBox2D.STEP, onStep);
  22. function onStep(evt:Event):void{
  23.     txt.text = (System.totalMemory / 100000).toFixed(2) + "mb";
  24. }
  25.  
  26. function buildRandomLevel():void{
  27.     // destroy all rigid bodies
  28.     for (var i:int = 0; i<levelParts.length; i++){
  29.         levelParts[i].destroy();
  30.     }
  31.     levelParts = [];
  32.     // create a bunch of circles and boxes
  33.     for (i = 0; i<16; i++){
  34.         var rad:Number = 0.4 ;
  35.         levelParts.push(sim.addCircle({x:1 + i * rad * 4, y : 2, radius:rad - Math.random()*0.3}));
  36.        
  37.         var rot:Number = Math.random() * TWO_PI;
  38.         levelParts.push(sim.addBox({x:4+Math.random() * i * 2, y:4+Math.random()*i,
  39.                     width:3, height:0.25, angle:rot, density:0}));
  40.     }
  41. }

This snippet creates and destroys a bunch of rigid bodies again and again.... On my macbook 2.6 Ghz intel core duo... the ram runs between 79mb and 112mb. I let it run for 40 minutes and this did not change - it always eventually returned down to 79mb.


Have a look at the swf...

Thanks to all the people who gave feedback that lead to the discover of these bugs.

Also posted in Box2D, QuickBox2D, pixel manipulation | Tagged , , , | 25 Comments

BitmapData Frame Animation (w/ linked list)

Actionscript:
  1. [SWF(width = 100, height = 100)]
  2. var circle:Shape = new Shape();
  3. with(circle.graphics) beginFill(0x000000), drawCircle(20,20,20);
  4.  
  5. var currFrame:Frame;
  6.  
  7. // populate the linked list
  8. generateAnimation();
  9.  
  10. var canvas:BitmapData = new BitmapData(stage.stageWidth,stage.stageHeight,false, 0x000000);
  11. addChild(new Bitmap(canvas));
  12. var loc:Point = new Point(20, 20);
  13.  
  14. addEventListener(Event.ENTER_FRAME, onLoop);
  15. function onLoop(evt:Event):void {
  16.     // clear the canvas
  17.     canvas.fillRect(canvas.rect, 0x000000);
  18.     // draw the current frame
  19.     canvas.copyPixels(currFrame.bitmap, currFrame.bitmap.rect, loc, null, null, true);
  20.     // get the next frame of the animation
  21.     currFrame = currFrame.next;
  22. }
  23.  
  24. // generate and capture 40 bitmaps by altering the colorTransform of the circle shape
  25. function generateAnimation():void{
  26.     var channel:uint = 0;
  27.     var ct:ColorTransform = new ColorTransform();
  28.     var increase:Boolean = true;
  29.     var firstFrame:Frame;
  30.     var pFrame:Frame;
  31.     for (var i:int = 0; i<40; i++){
  32.         if (increase){
  33.            channel += 10;
  34.            if (channel == 200){
  35.               increase = false;  
  36.            }
  37.         }else{
  38.            channel -= 10;
  39.         }
  40.         ct.color = channel <<16 | channel <<8 | channel;
  41.         circle.transform.colorTransform = ct;
  42.         // populate linked list
  43.         currFrame = capture(circle);
  44.         if (pFrame){
  45.            pFrame.next = currFrame;
  46.         }
  47.         if (i == 0){
  48.            firstFrame = currFrame;
  49.         }
  50.         pFrame = currFrame;
  51.     }
  52.     // close the list
  53.     currFrame.next = firstFrame;
  54.     currFrame = firstFrame;
  55. }
  56.  
  57. // create the Frame instance and draw the circle to it
  58. // preserving the colorTransform information
  59. function capture(target:Shape):Frame{
  60.     var frame:Frame = new Frame();
  61.     frame.bitmap = new BitmapData(target.width, target.height, true, 0x00000000);
  62.     frame.bitmap.draw(target, null, target.transform.colorTransform);
  63.     return frame;
  64. }

Requires this little Frame class

Actionscript:
  1. package {
  2.     import flash.display.*;
  3.     final public class Frame{
  4.         public var bitmap:BitmapData;
  5.         public var next:Frame;
  6.     }
  7. }

This is a small test I did today to see how easy it would be to use a circular linked list to loop an animation of bitmaps. I did this because I was thinking about using some animated sprites in conjunction with Utils3D.projectVectors() to do an orthographic 3D demo with lots of animating sprites. In the past I've had up to 7,000 animated sprites running nicely using arrays and copyPixels... figured it would be interesting to try and do the same with a circular linked list.

When compiled, this test simply draws a circle that fades from black to gray and back again... Pretty boring, but I threw it up over at wonderfl anyway... check it out.

I recently saw a few tweets (forget who from) about using the final keyword on linked list nodes... haven't tested it myself but it's supposed to be faster...

Also posted in BitmapData, Data Structures, misc, pixel manipulation | Tagged , , | 1 Comment