Monthly Archives: September 2009

QuickBox2D 1.0 Features

Here is a quick list of the new features in QuickBox2D along with links to the docs.

1) The QuickBox2D.STEP event:
A few releases ago, frim (frame rate independent motion) was added to QuickBox2D. However, there was no way to execute calls to b2Body.ApplyImpulse() b2Body.SetLinearVelocity() etc… along with the b2World.Step() method. This meant that you couldn’t call these methods in a way that would truly maintain frim. As you’ll see in upcoming demos, rather than doing key controls or additional simulation logic in an enterframe event, I’ll be listening for the QuickBox2D.STEP event. This is executed every time a timeStep occurs. If frim is on, this the STEP event will be executed independently of frameRate.

2) Some features were added to help trigger events at specific times in the simulation. See:

QuickBox2D.totalTimeSteps
QuickBox2D.addTimeStepSequence

…for an example of addTimeStepSequence() check out this recent post.

3) Some additional control was added to mouse dragging for QuickBox2D. There is a new property in the QuickBox2D params object called customMouse. When set to true, this enables you to pass in mouse coordinates rather than having QuickBox2D automatically use the coordinates of the DisplayObject that all the rigid bodies are being drawn to. This feature is useful if you are rendering using a 3D engine. See:

QuickBox2D customMouse
QuickBox2D.setMouse()

4) A few features were added to make contact points easy to work with. See:

QuickBox2D.addContactListener()
QuickContacts

…I’ll be posting a few demos showing how to use QuickContacts - here are the first two (more to come in the next few days):
part 1
part 2

Posted in QuickBox2D | Tagged , , , | 1 Comment

QuickBox2D Contacts Part 2

Actionscript:
  1. import com.actionsnippet.qbox.*;
  2.  
  3. [SWF(width = 800, height = 600, backgroundColor = 0x000000, frameRate=60)]
  4.  
  5. var sim:QuickBox2D = new QuickBox2D(this);
  6.  
  7. sim.createStageWalls();
  8.  
  9. var boxA:QuickObject = sim.addBox({x:3, y:3, width:2, height:2});
  10. var boxB:QuickObject = sim.addBox({x:3, y:6, width:2, height:2});
  11.  
  12. // add a few extra circles to show that there are other contacts
  13. // occuring
  14. for (var i:int = 0; i<10; i++){
  15.     sim.addCircle({x:5 + i, y:4, radius:0.1 + Math.random()});
  16. }
  17.  
  18. sim.start();
  19. sim.mouseDrag();
  20.  
  21. // when boxA touches boxB change their alpha values to 50%
  22. var contacts:QuickContacts = sim.addContactListener();
  23. contacts.addEventListener(QuickContacts.ADD, onAdd);
  24. contacts.addEventListener(QuickContacts.PERSIST, onPersist);
  25. contacts.addEventListener(QuickContacts.REMOVE, onRemove);
  26. function onAdd(evt:Event):void{
  27.     if(contacts.isCurrentContact(boxA, boxB)){
  28.         boxA.userData.alpha = 0.5;
  29.         boxB.userData.alpha = 0.5;
  30.     }
  31. }
  32. function onPersist(evt:Event):void{
  33.     if(contacts.isCurrentContact(boxA, boxB)){
  34.         boxA.userData.alpha = 0.5;
  35.         boxB.userData.alpha = 0.5;
  36.     }
  37. }
  38. function onRemove(evt:Event):void{
  39.     if(contacts.isCurrentContact(boxA, boxB)){
  40.         boxA.userData.alpha = 1;
  41.         boxB.userData.alpha = 1;
  42.     }
  43. }

Note: This snippet requires QuickBox2D 1.0 or greater

This is another example showing how to make use of QuickBox2D contacts. In this example three contact events are used ADD, PERSIST and REMOVE. When the two boxes are touching their alpha values are set to 50% - otherwise their alpha values are at 100%.


Have a look at the swf...

A Little Detail About the Events

The ADD event is dispatched when a new b2ContactPoint is generated. The PERSIST event is dispatched as long as the b2ContactPoint exists for more than one timeStep - and from what I can tell, is dispatched until the rigid bodies it is associated with go to sleep. The REMOVE event is called when the b2ContactPoint is removed, meaning the rigid bodies that caused the creating of the b2ContactPoint are no longer touching.

You need to be careful with the code that you place inside the listener functions for these events. The reason being that these events are called many many times for every contact point in the simulation.

Posted in Box2D, QuickBox2D | Tagged , , , , | 2 Comments

QuickBox2D Contacts Part 1

Actionscript:
  1. import com.actionsnippet.qbox.*;
  2. import Box2D.Common.Math.*;
  3.  
  4. [SWF(width = 800, height = 600, backgroundColor = 0x000000, frameRate=60)]
  5.  
  6. var sim:QuickBox2D = new QuickBox2D(this, {debug:false, frim:true});
  7.  
  8. sim.createStageWalls();
  9.  
  10. var boxA:QuickObject = sim.addBox({x:3, y:3, width:2, height:2, fillColor:0xFF0000});
  11. var boxB:QuickObject = sim.addBox({x:3, y:6, width:2, height:2, fillColor:0xFF0000});
  12.  
  13. sim.start();
  14. sim.mouseDrag();
  15.  
  16. // when boxA touches boxB a circle QuickObject is created
  17. var contacts:QuickContacts = sim.addContactListener();
  18. // listen for contact points being added
  19. contacts.addEventListener(QuickContacts.ADD, onAdd);
  20. function onAdd(evt:Event):void{
  21.     // see if this contact event is associated with boxA and boxB
  22.     if(contacts.isCurrentContact(boxA, boxB)){
  23.         // get the location of the collision in world space
  24.         var loc:b2Vec2 = contacts.currentPoint.position;
  25.         // you cannot create new QuickObjects inside this listener function
  26.         // so we just give a 5 ms delay
  27.         setTimeout(sim.addCircle, 5, {x:loc.x, y:loc.y});
  28.     }
  29. }

Note: This snippet requires QuickBox2D 1.0 or greater

I've created a few simple examples to show how to use QuickBox2D contact listeners. This is the first one. When two boxes collide circles are added to the simulation at the point of collision.


Have a look at the swf...

Posted in Box2D, QuickBox2D | Tagged , , , , | 10 Comments

QuickBox2D 1.0

QuickBox2D 1.0 is ready. It contains a bunch of small bug fixes and a few new features that I'll be demoing in the next few posts. The main new features relate to collision detection and simple event sequencing.

Go download it from here...

I also spent some time updating the docs.... everything is documented... I may add additional documentation text over the next few days...

A detailed tutorial for QuickBox2D is also in the works...

[EDIT]

Also, if you find any bugs send me an e-mail (see about page for e-mail)... if there are any bugs left I'd like to fix the asap.... You can also feel free to e-mail any API suggestions...

Posted in Box2D, QuickBox2D | Tagged , , , , | 2 Comments

drawTriangles() Cubes

Actionscript:
  1. private function addCube(xp:Number, yp:Number, zp:Number, w:Number, h:Number, leng:Number):void{
  2.             var hw:Number = w * 0.5;
  3.             var hh:Number = h * 0.5;
  4.             var hl:Number = leng * 0.5;
  5.             var xA:Number = xp - hw;
  6.             var xB:Number = hw + xp;
  7.             var yA:Number = yp - hh;
  8.             var yB:Number = hh + yp;
  9.             var zA:Number = zp - hl;
  10.             var zB:Number = hl + zp;
  11.             _verts.push(xA, yA, zA,
  12.                         xB, yA, zA,
  13.                         xA, yB, zA,
  14.                         xB, yB, zA,
  15.                         xA, yA, zB,
  16.                         xB, yA, zB,
  17.                         xA, yB, zB,
  18.                         xB, yB, zB);
  19.            
  20.             var index:int = _boxIndex * 8;
  21.             var i0:int = index, i1:int = index + 1, i2:int = index + 2;
  22.             var i3:int = index + 3,  i4:int = index + 4, i5:int = index + 5;
  23.             var i6:int = index + 6, i7:int = index + 7;
  24.             _indices.push(i0, i1, i2,
  25.                           i1, i3, i2,
  26.                           i6, i7, i4,
  27.                           i7, i5, i4,
  28.                           i1, i5, i3,
  29.                           i7, i3, i5,
  30.                           i4, i5, i0,
  31.                           i1, i0, i5,
  32.                           i2, i6, i0,
  33.                           i0, i6, i4,
  34.                           i2, i3, i6,
  35.                           i3, i7, i6);
  36.                          
  37.             _faces.push(new Face(), new Face(), new Face(),
  38.                         new Face(),  new Face(), new Face(),
  39.                         new Face(), new Face(), new Face(),
  40.                         new Face(), new Face(), new Face());
  41.             _uvts.push(Math.random(), Math.random(), 0,
  42.                        Math.random(), Math.random(), 0,
  43.                        Math.random(), Math.random(), 0,
  44.                        Math.random(), Math.random(), 0,
  45.                        Math.random(), Math.random(), 0,
  46.                        Math.random(), Math.random(), 0,
  47.                        Math.random(), Math.random(), 0,
  48.                        Math.random(), Math.random(), 0);
  49.             _boxIndex++;
  50.         }

Lately I've been posting large code snippets... so today I'm highlighting part of a larger snippet - The above code is the heart of a small experiment I created this morning. It sets up a cube for use with drawTraingles().

The rest of the code can be read here:
Cubes3D.as

Have a look at the swf here...


I also put it on wonderfl...

Posted in 3D, Graphics, Vector, matrix, motion | Tagged , , | 6 Comments

Calculate Surface Area and Volume of a Sphere

Actionscript:
  1. var rad:Number = 1;
  2.  
  3. var surfaceArea:Number = sphereSurfaceArea(rad);
  4. var volume:Number = sphereVolume(rad)
  5. trace("surface area: ", surfaceArea);
  6. trace("volume:", volume);
  7. trace("volume / surface area:", volume / surfaceArea);
  8.  
  9. function sphereSurfaceArea(r:Number):Number{
  10.     return 4 * Math.PI * r * r;
  11. }
  12.  
  13. function sphereVolume(r:Number):Number{
  14.     return r * r * r * (4.0/3.0) * Math.PI;
  15. }
  16.  
  17. /*outputs:
  18. surface area:  12.566370614359172
  19. volume: 4.1887902047863905
  20. volume / surface area: 0.3333333333333333
  21. */

Last night I was feeling curious about sphere volume and sphere surface area... I used WolframAlpha to find the neccessary equations and then wrote the above code snippet...

Check out how WolframAlpha does it:
surface area of a sphere
surface area of a sphere with radius 10
sphere volume
sphere volume with radius 10

Posted in Math, misc | Tagged , , , | 2 Comments

QuickBox2D addTimeStepSequence() Preview

Actionscript:
  1. import com.actionsnippet.qbox.*;
  2.  
  3. [SWF(width = 800, height = 600, backgroundColor = 0xFFFFFF, frameRate=60)]
  4.  
  5. // hide everything for 300 ms
  6. visible = false;
  7. setTimeout(function():void{ visible = true}, 300);
  8.  
  9. var canvas:MovieClip = MovieClip(addChild(new MovieClip()));
  10.  
  11. var sim:QuickBox2D = new QuickBox2D(canvas, {debug:true});
  12.  
  13. sim.setDefault({fillColor:0x666666, lineAlpha:0})
  14. sim.createStageWalls();
  15.  
  16. var boxA:QuickObject = makeLever(6 , 17.5, 9, "right", 0.7);
  17. var circleA:QuickObject = sim.addCircle({x:2, y:3, radius:0.5, mass:4});
  18. sim.addBox({x:15, y:12, width:2, height:0.5, density:0})
  19. var circleB:QuickObject = sim.addCircle({x:16, y:11, radius:0.5, mass:4, friction:0.2, fillColor:0});
  20. sim.addBox({x:20.5, y:12, width:2, height:0.3, angle:-0.6, restitution:4.6, density:0})
  21. var boxB:QuickObject = makeLever(20 , 17.5, 8, "right", 1);
  22. sim.addBox({x:9, y:9, width:2, height:0.5, density:0});
  23. var circleC:QuickObject = sim.addCircle({x:9, y:9, radius:0.5, mass:4, friction:0.2, fillColor:0});
  24. sim.addBox({x:7, y:12, width:2, height:0.5, angle:-0.3, density:0, restitution:2});
  25. sim.addBox({x:3, y:7, width:2, height:0.5, angle:Math.PI/2 - 0.22, density:0, restitution:3});
  26. sim.addBox({x:13, y:15, width:2, height:0.5, density:0, angle:0.3, restitution:1});
  27. sim.addBox({x:25.5, y:7, width:2, height:0.3, angle:-0.2, restitution:0.5, density:0})
  28. sim.addBox({x:26, y:10, width:1, height:1, density:0,restitution:0.3});
  29. sim.addBox({x:25, y:19, width:2, height:0.5, density:0, restitution:3.5, angle:-0.99});
  30. sim.addBox({x:1, y:17, width:0.3, height:2, density:0, angle:-0.15, restitution:0.999});
  31. sim.addBox({x:0.7, y:11, width:0.3, height:2, density:0, angle:-0.19, restitution:20})
  32. sim.addBox({x:0.4, y:11.5, width:1, height:0.3, density:0})
  33.  
  34. function makeLever(xp:Number, yp:Number, boxWidth:Number, dir:String, off:Number=0, hasBox:Boolean=true):QuickObject{
  35.     var angle:Number, xpos:Number, weight:QuickObject
  36.     if (dir == "right"){
  37.         angle = 0.43;
  38.         xpos = xp + boxWidth / 2 - off;
  39.     }else{
  40.         angle = -0.43;
  41.         xpos = xp - boxWidth / 2 + off;
  42.     }
  43.     if (hasBox){
  44.       weight = sim.addBox({x:xpos , y:yp, width:0.5, height:0.5, angle:angle, fillColor:0});
  45.     }
  46.     var plank:QuickObject = sim.addBox({x:xp, y:yp, width:boxWidth, height:0.5, angle:angle});
  47.     var fulcrum:QuickObject = sim.addPoly({x:xp, y:yp, verts:[[0,0, 1,2, -1,2]], density:0})
  48.     sim.addJoint({type:"revolute", a:plank.body, b:fulcrum.body, collideConnected:false});
  49.     return weight;
  50. }
  51.  
  52. sim.start();
  53.  
  54. // new feature, calls a function after a specific number of box2D timeSteps
  55. sim.addTimeStepSequence({time:70, callback:cam, args:[boxA]},
  56.                         {time:150, callback:cam, args:[circleB]},
  57.                         {time:200, callback:cam, args:[boxB, 1.3]},
  58.                         {time:580, callback:cam, args:[circleC]},
  59.                         {time:700, callback:cam, args:[circleC, 1.1]},
  60.                         {time:810, callback:cam, args:[boxB, 1.4]},
  61.                         {time:870, callback:cam, args:[boxB, 3]},
  62.                         {time:890, callback:cam, args:[boxB, 1.1]},
  63.                         {time:1200,callback:cam, args:[boxB, 1]});
  64.  
  65. // set values for matrix pan and zoom
  66. function cam(quickObj:QuickObject, scale:Number=-1):void{
  67.     currQuick = quickObj;
  68.     if (scale != -1){
  69.         scaleDest = scale;
  70.     }
  71. }                                
  72.                
  73. // matrix pan and zoom
  74. var scale:Number = 1;
  75. var scaleDest:Number = 1.2;
  76. var down:Boolean = false;
  77. var dx:Number = 0, dy:Number = 0, time:Number = 0;
  78. var currQuick:QuickObject = circleA;
  79. addEventListener(Event.ENTER_FRAME, onLoop);
  80. function onLoop(evt:Event):void {
  81.    scale += (scaleDest - scale) / 8;
  82.    dx += (currQuick.x*30 - dx) / 8;
  83.    dy += (currQuick.y*30 - dy) / 8;
  84.    // matrix zoom/pan
  85.     var m:Matrix = canvas.transform.matrix;
  86.    m.identity();
  87.    m.translate(-dx,-dy);
  88.    m.scale(scale, scale);
  89.    m.translate(dx,dy);
  90.    canvas.transform.matrix = m;
  91. }

This is a preview of an upcoming feature for the QuickBox2D 1.0 release. It shows how addTimeStepSequence() is going to work. QuickBox2D 1.0 will have an internal timer counting the number of world steps that Box2D has taken. This is really useful for sequencing in conjunction with QuickBox2D's default FRIM (framerate independent motion).

This snippet uses addTimeStepSequence() to move a 2D camera around the simulation (from yesterdays post) - the camera pans and zooms... If you'd like to use addTimeStepSequence() simply replace your QuickBox2D.as file with this updated one:

I plan to release QuickBox2D 1.0 on monday - so I didn't think it made sense to do alpha 110 just for this one change...


Have a look at the swf....

Posted in Box2D, QuickBox2D, motion | Tagged , , , | 1 Comment

QuickBox2D Vaguely Goldberg-esque

Actionscript:
  1. import com.actionsnippet.qbox.*;
  2. import Box2D.Common.Math.*;
  3. import Box2D.Collision.Shapes.*;
  4.  
  5. [SWF(width = 800, height = 600, backgroundColor = 0xFFFFFF, frameRate=60)]
  6.  
  7. // hide everything for 300 ms
  8. visible = false;
  9. setTimeout(function():void{ visible = true}, 300);
  10.  
  11. var sim:QuickBox2D = new QuickBox2D(this, {debug:false});
  12.  
  13. sim.setDefault({fillColor:0x666666, lineAlpha:0})
  14. sim.createStageWalls();
  15.  
  16. makeLever(6 , 17.5, 9, "right", 0.7);
  17.  
  18. var circleA:QuickObject = sim.addCircle({x:2, y:3, radius:0.5, mass:4});
  19.  
  20. sim.addBox({x:15, y:12, width:2, height:0.5, density:0})
  21.  
  22. sim.addCircle({x:16, y:11, radius:0.5, mass:4, friction:0.2, fillColor:0});
  23.  
  24. sim.addBox({x:20.5, y:12, width:2, height:0.3, angle:-0.6, restitution:4.6, density:0})
  25.  
  26. makeLever(20 , 17.5, 8, "right", 1);
  27.  
  28. sim.addBox({x:9, y:9, width:2, height:0.5, density:0});
  29.  
  30. sim.addCircle({x:9, y:9, radius:0.5, mass:4, friction:0.2, fillColor:0});
  31.  
  32. sim.addBox({x:7, y:12, width:2, height:0.5, angle:-0.3, density:0, restitution:2});
  33.  
  34. sim.addBox({x:3, y:7, width:2, height:0.5, angle:Math.PI/2 - 0.22, density:0, restitution:3});
  35.  
  36. sim.addBox({x:13, y:15, width:2, height:0.5, density:0, angle:0.3, restitution:1});
  37.  
  38. sim.addBox({x:25.5, y:7, width:2, height:0.3, angle:-0.2, restitution:0.5, density:0})
  39.  
  40. sim.addBox({x:26, y:10, width:1, height:1, density:0,restitution:0.3});
  41.  
  42. sim.addBox({x:25, y:19, width:2, height:0.5, density:0, restitution:3.5, angle:-0.99});
  43.  
  44. sim.addBox({x:1, y:17, width:0.3, height:2, density:0, angle:-0.15, restitution:0.999});
  45.  
  46. sim.addBox({x:0.7, y:11, width:0.3, height:2, density:0, angle:-0.19, restitution:20})
  47.  
  48. sim.addBox({x:0.4, y:11.5, width:1, height:0.3, density:0})
  49.  
  50. function makeLever(xp:Number, yp:Number, boxWidth:Number, dir:String, off:Number=0, hasBox:Boolean=true):QuickObject{
  51.     var angle:Number, xpos:Number, weight:QuickObject
  52.     if (dir == "right"){
  53.         angle = 0.43;
  54.         xpos = xp + boxWidth / 2 - off;
  55.     }else{
  56.         angle = -0.43;
  57.         xpos = xp - boxWidth / 2 + off;
  58.     }
  59.    
  60.     if (hasBox){
  61.       weight = sim.addBox({x:xpos , y:yp, width:0.5, height:0.5, angle:angle, fillColor:0});
  62.     }
  63.  
  64.     var plank:QuickObject = sim.addBox({x:xp, y:yp, width:boxWidth, height:0.5, angle:angle});
  65.     var fulcrum:QuickObject = sim.addPoly({x:xp, y:yp, verts:[[0,0, 1,2, -1,2]], density:0})
  66.     sim.addJoint({type:"revolute", a:plank.body, b:fulcrum.body, collideConnected:false});
  67.     return weight;
  68. }
  69.  
  70. sim.start();

Just playing around with QuickBox2D and brainstorming about a few features for the first non-alpha release. If you have any feature suggestions, please feel free to leave them in the comments of this post (see the end of this post for a list features to come in QuickBox2D 1.0).


Have a look at the swf...

Upcoming Features for QuickBox2D
Simplified collision detection - will hopefully be something like hitTest for QuickObject instances.

QuickBox2D.totalTimeSteps - variable that keeps track of how many times b2World.Step() was called - useful for simple sequencing.

QuickBox2D.addTimeStepEvent(callAt:Number, callback:Function) - calls a function when QuickBox2D.totalTimeSteps is equal to the callAt value.

QuickBox2D.stepEvent - an event dispatched every time b2World.Step() is called.

New Renderer [probably not for 1.0 release]
I've been toying with the idea of creating a new renderer for QuickBox2D. Currently all rigid bodies are DisplayObjects... this is great if you plan on skinning all your rigid bodies, but if you just have flat colors it is slower than debug draw - also, debug draw mode could be optimized a good deal. So I may create a simpler, faster renderer that draws to one Graphics instance (like debug draw mode) - but abides by QuickBox2D's simple rendering params like lineColor, fillColor, lineAlpha etc...

I also need to decide how to skin the rest of the joints, currently skins only work for distance joints...

Posted in Box2D, QuickBox2D, motion | Tagged , , , , | 4 Comments

White Circles Black Circles

Actionscript:
  1. [SWF(backgroundColor=0xFFFFFF, width=500, height=500)]
  2.  
  3. var hsw:Number = stage.stageWidth / 2;
  4. var hsh:Number = stage.stageHeight / 2;
  5. var pointNum:int = 200;
  6. var points3D:Vector.<Number> = new Vector.<Number>();
  7. var points2D:Vector.<Number> = new Vector.<Number>();
  8. var uvts:Vector.<Number> = new Vector.<Number>();
  9. var sorted:Array = [];
  10. var thickness:Vector.<Number> = new Vector.<Number>();
  11. var radii:Vector.<Number> = new Vector.<Number>();
  12. var colors:Vector.<uint> = new Vector.<uint>();
  13.  
  14. var pnt:Point = new Point();
  15. var m:Matrix3D = new Matrix3D();
  16. var v:Vector3D = new Vector3D();
  17.  
  18. for (var i:int = 0; i<pointNum; i++){
  19.     v.x = Math.random()*1000-500;
  20.     m.identity();
  21.     m.appendRotation(Math.random()*360, Vector3D.X_AXIS);
  22.     m.appendRotation(Math.random()*360, Vector3D.Y_AXIS);
  23.     m.appendRotation(Math.random()*360, Vector3D.Z_AXIS);
  24.     v = m.transformVector(v);
  25.     points3D.push(v.x, v.y, v.z);
  26.     points2D.push(0,0);
  27.     uvts.push(0,0,0);
  28.     sorted.push({});
  29.     thickness.push(Math.random() * Math.random() * 50 + 4);
  30.     radii.push(Math.random() * 100 + 10);
  31.     colors.push([0xFFFFFF, 0x000000][int(Math.random()*2)]);
  32. }
  33. points3D.fixed = true;
  34. points2D.fixed = true;
  35. uvts.fixed = true;
  36. thickness.fixed = true;
  37. radii.fixed = true;
  38. colors.fixed = true;x
  39. var p:PerspectiveProjection = new PerspectiveProjection();
  40. var proj:Matrix3D = p.toMatrix3D();
  41. var dx:Number = 0, dy:Number = 0;
  42. addEventListener(Event.ENTER_FRAME, onLoop);
  43. function onLoop(evt:Event):void {
  44.     var i:int, j:int;
  45.     dx += (mouseX - dx) / 4;
  46.     dy += (mouseY - dy) / 4;
  47.     m.identity();
  48.     m.appendRotation(dx, Vector3D.Y_AXIS);
  49.     m.appendRotation(dy, Vector3D.X_AXIS);
  50.     m.appendTranslation(0, 0, 1000);
  51.     m.append(proj);
  52.     Utils3D.projectVectors(m, points3D, points2D, uvts);
  53.     for (i = 0, j = 0; i<points2D.length; i+=2, j++){
  54.         sorted[j].x = points2D[i] + hsw;
  55.         sorted[j].y = points2D[i + 1] + hsh;
  56.         sorted[j].z = uvts[j * 3 + 2];
  57.         sorted[j].color = colors[j];
  58.         sorted[j].radius = radii[j];
  59.         sorted[j].thickness = thickness[j];
  60.     }
  61.     sorted.sortOn("z", Array.NUMERIC);
  62.     graphics.clear();
  63.     for(i = 0; i<sorted.length; i++){
  64.         var element:Object = sorted[i];
  65.         var zpos:Number = element.z * 18000;
  66.         graphics.lineStyle(element.thickness, element.color);
  67.         graphics.drawCircle(element.x, element.y, zpos + element.radius);
  68.         graphics.endFill();
  69.     }
  70. }

Was just looking at the stills from yesterdays post and noticing how much I actually like the way they looked. Really simple, just black and white cirlces - reminded me a bit of this flash experiment by Jared Tarbell (from 2002).

So I popped the same kind of black and white circles into the z-sorting 3D snippet I've been using recently and came up with this...


Have a look at the swf...


Posted in Uncategorized | Tagged , , | Leave a comment

Matrix Zoom and Pan

Actionscript:
  1. [SWF(width=600, height=600, frameRate=30)]
  2. var sw:Number = stage.stageWidth;
  3. var sh:Number = stage.stageHeight;
  4.  
  5. var s:Shape = Shape(addChild(new Shape()));
  6.  
  7. var scale:Number = 1;
  8. var scaleDest:Number = 1;
  9. var down:Boolean = false;
  10. var dx:Number = 0, dy:Number = 0, time:Number = 0;
  11.  
  12. buttonMode = true;
  13.  
  14. addInstructions();
  15. vectorTexture();
  16.  
  17. stage.addEventListener(MouseEvent.MOUSE_DOWN, onDown);
  18. stage.addEventListener(MouseEvent.MOUSE_UP, onUp);
  19. addEventListener(Event.ENTER_FRAME, onLoop);
  20.  
  21. function addInstructions():void{
  22.     var instruct:Sprite = Sprite(addChild(new Sprite()));
  23.     with (instruct.graphics) beginFill(0x666666), drawRect(0,0,270, 30);
  24.     instruct.x = instruct.y = 20;
  25.     var txt:TextField = TextField(instruct.addChild(new TextField()));
  26.     txt.defaultTextFormat = new TextFormat("Verdana", 11);
  27.     txt.x = txt.y = 5;
  28.     txt.selectable = false;
  29.     with (txt) textColor = 0xFFFFFF, autoSize = "left", text = "Click and hold to zoom, move mouse to pan";
  30. }
  31.  
  32. function vectorTexture():void{
  33.     var cols:Vector.<uint> = Vector.<uint>([0xFFFFFF, 0x000000]);
  34.     var rnd:Vector.<Number> = new Vector.<Number>(6, true);
  35.    
  36.     for(var i:int = 0 ; i<50; i++){
  37.         with(s.graphics){
  38.             lineStyle(Math.random() * 50 + 2, cols[int(Math.random()*cols.length)]);
  39.             drawCircle(Math.random() * sw, Math.random() * sh, 10 + Math.random() * Math.random() * 400);
  40.         }
  41.     }
  42.     s.graphics.lineStyle(20, 0xCCCCCC);
  43.     s.graphics.drawRect(0, 0,sw, sh);
  44. }
  45.  
  46. function onDown(evt:MouseEvent):void{ down = true; }
  47. function onUp(evt:MouseEvent):void{ down = false; }
  48. function onLoop(evt:Event):void {
  49.    if (down){
  50.      scaleDest *= 1.05;  
  51.      time = 0;
  52.    }else{
  53.      time++;
  54.      // zoom out after 30 iterations
  55.      if (time == 30){
  56.          scaleDest = 1;  
  57.      }
  58.    }
  59.    scale += (scaleDest - scale) / 4;
  60.    if (scale> 10) scale = scaleDest = 10;
  61.    
  62.    dx += (mouseX - dx) / 4;
  63.    dy += (mouseY - dy) / 4;
  64.    if (dx <0) dx = 0;
  65.    if (dy <0) dy = 0;
  66.    if (dx> sw) dx = sw;
  67.    if (dy> sh) dy = sh;
  68.    
  69.    // matrix zoom/pan
  70.    var m:Matrix = s.transform.matrix;
  71.    m.identity();
  72.    m.translate(-dx,-dy);
  73.    m.scale(scale, scale);
  74.    m.translate(dx,dy);
  75.    s.transform.matrix = m;
  76. }

I haven't been by the computer much these last two weeks - been traveling. Going back to nyc tomorrow so I'll go back to posting once a day.

This snippet uses a transformation matrix to zoom in and pan a Sprite instance. For demo purposes I filled the sprite with a few circles - but you'd likely be using this with a vector image of a map, a floor plan or some other graphic that warrants zooming and panning.

Back around flash 7 (I think) before the Matrix class was introduced we used to have to use MovieClip nesting to achieve this effect.


Have a look at the swf...


Posted in Graphics, matrix, motion | Tagged , , | Leave a comment