Monthly Archives: May 2009

QuickBox2D Groups

Actionscript:
  1. import com.actionsnippet.qbox.*;
  2.  
  3. [SWF (backgroundColor=0xAA0000, width=700, height=600, frameRate=60)]
  4.  
  5. var sim:QuickBox2D = new QuickBox2D(this);
  6.  
  7. sim.createStageWalls();
  8.  
  9. /**
  10. create a dancing pill
  11. */
  12. // all x and y coords are relative to the center of the group
  13. var partA:QuickObject = sim.addCircle({x:-1, y:0, radius:0.5, restitution:.9});
  14. var partB:QuickObject = sim.addCircle({x:1, y:0, radius:0.5, restitution:.9});
  15. var partC:QuickObject = sim.addBox({x:0, y:0, width:2, height:1});
  16. // all the parts are passed into the objects array
  17. // addGroup() groups the parts together into one rigid body
  18. var pill:QuickObject = sim.addGroup({objects:[partA, partB, partC], x:3, y:3, angle:0.3});
  19.  
  20. /**
  21. create another group
  22. */
  23. partA = sim.addCircle({x:0, y:0, radius:1});
  24. partB = sim.addBox({x:0, y:1, width:1, height:1, fillColor:0x666666});
  25. partC = sim.addBox({x:0, y:-1, width:1, height:1, fillColor:0x666666});
  26. sim.addGroup({objects:[partA, partB, partC], x:8, y:3, angle:0.3});
  27.  
  28. /**
  29. create two circles linked together by a stretchy joint
  30. */
  31. partA = sim.addCircle({x:15, y:3, fillColor:0x000000, anglularDamping:1});
  32. partB = sim.addCircle({x:17, y:3, fillColor:0xFFFFFF, anglularDamping:1});
  33. // if x1, y1, x2 and y2 properties are not set, the joint is automatically placed
  34. // at the b2Body's center
  35. sim.addJoint({a:partA.body, b:partB.body, frequencyHz:1});
  36.  
  37. sim.start();
  38. sim.mouseDrag();

You'll need QuickBox2D Alpha 106 to run this... This snippet demo's the addGroup() method, which allows for easy grouping of shapes. I updated the docs today to feature a simple explanation of how this works.


Have a look at the swf here...

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

QuickBox2D Polys

Actionscript:
  1. import com.actionsnippet.qbox.*;
  2.  
  3. [SWF(backgroundColor=0x000000, width=700, height=600)]
  4.  
  5. var sim:QuickBox2D = new QuickBox2D(this);
  6.  
  7. sim.setDefault({fillColor:0x003366, lineColor:0x2B80D5});
  8. sim.createStageWalls();
  9.  
  10. var i:int = 0;
  11. for (i= 0; i<10; i++){
  12.   sim.addCircle({x:5 + i, y:7, radius:0.3, linearDamping:1, angularDamping:1, fillColor:0x78B4C2, isBullet:true})
  13. }
  14.  
  15. for (i= 0; i<2; i++){
  16.     var poly:Array = [];
  17.     var r:Number = 3;
  18.     var step:Number = Math.PI / 6;
  19.     for (var t:Number = 0; t<=Math.PI; t+=step){
  20.         poly.push(r * Math.cos(t));
  21.         poly.push(r * Math.sin(t));
  22.     }
  23.     r = 2;
  24.     for (t = Math.PI; t>= -step; t-=step){
  25.         poly.push(r * Math.cos(t));
  26.         poly.push(r * Math.sin(t));
  27.     }
  28.     // using points instead of verts causes QuickBox2D to triangulate the polygon
  29.     // the wireframe boolean changes rendering style for polys
  30.     sim.addPoly({x:4 + i *7, y:16, points:poly, wireframe:Boolean(i), linearDamping:1.5, angularDamping:1});
  31. }
  32.  
  33. sim.start();
  34. sim.mouseDrag();

I just uploaded QuickBox2D Alpha 106 which includes a few bug fixes and support for compound shapes and easier polys. I used the algorithm from yesterdays post to significantly simplify the way QuickBox2D handles the description of polygons.

You'll need QuickBox2D Alpha 106 or greater, if you want to test this....


or just have a look at the demo here.

This triangulation is really better suited for 3D stuff - Box2D supports multiple convex polygons in one rigid body... this algorithm makes more shapes (triangles) than Box2D needs - I'll probably swap out the algorithm in the near future.

Tomorrow I'll be posting a demo about the way QuickBox2D simplifies compound shapes. I have yet to update the docs to include the new features of Alpha 106. That will happen along with tomorrows post.

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

Polygon Triangulation

Actionscript:
  1. var triangulate:Triangulate = new Triangulate();
  2.  
  3. var poly:Array=[];
  4.  
  5. stage.addEventListener(MouseEvent.MOUSE_DOWN, onDown);
  6. function onDown(evt:MouseEvent):void {
  7.     poly.push(new Pnt(mouseX, mouseY));
  8. }
  9.  
  10. addEventListener(Event.ENTER_FRAME, onLoop);
  11. function onLoop(evt:Event):void {
  12.     var i:int;
  13.     graphics.clear();
  14.     var verts:Array=triangulate.process(poly);
  15.  
  16.     if (verts==null) {
  17.         // draw a red polygon if there is some kind of error,
  18.         // or if there are too few points on the poly
  19.         if (poly.length>1) {
  20.             graphics.lineStyle(0,0xFF0000);
  21.             graphics.moveTo(poly[0].x, poly[0].y);
  22.             for (i = 1; i<poly.length; i++) {
  23.                 graphics.lineTo(poly[i].x, poly[i].y);
  24.             }
  25.         }
  26.     }else{
  27.         // draw the triangulated polygon
  28.         var tcount:int = verts.length / 3;
  29.         graphics.lineStyle(0,0x000000);
  30.         for (i = 0; i<tcount; i++) {
  31.             var index:int = i * 3;
  32.             var p1:Pnt=verts[index];
  33.             var p2:Pnt=verts[index+1];
  34.             var p3:Pnt=verts[index+2];
  35.             graphics.moveTo(p1.x,p1.y);
  36.             graphics.lineTo(p2.x,p2.y);
  37.             graphics.lineTo(p3.x,p3.y);
  38.             graphics.lineTo(p1.x,p1.y);
  39.         }
  40.     }
  41. }

The above demo's a class that triangulates a polygon given a list of points. To test this snippet you'll need the Pnt and Triangulate Classes, which you can download or copy from below.

Polygon triangulation is useful for lots of things... I first found that I needed it back in my Director days. I wanted to be able to draw a polygon and then extrude it into 3D space - in order to do this I needed to triangulate the polygon that was drawn. Luckily there was an undocumented feature in Lingo that did the triangulation. I'll probably do an extrusion demo soon. I've been looking into this to make the QuickBox2D polygon stuff a little easier.


Take a look at the swf here

Download all source and fla here....

Here is the Triangulate class:

Actionscript:
  1. /**
  2. This code is a quick port of code written in C++ which was submitted to
  3. flipcode.com by John W. Ratcliff  // July 22, 2000
  4. See original code and more information here:
  5. http://www.flipcode.com/archives/Efficient_Polygon_Triangulation.shtml
  6.  
  7. ported to actionscript by Zevan Rosser
  8. www.actionsnippet.com
  9. */
  10.  
  11. package {
  12.    
  13.     public class Triangulate {
  14.        
  15.         private const EPSILON:Number = 0.0000000001;
  16.        
  17.         public function Triangulate(){}
  18.        
  19.         public function process(contour:Array):Array{
  20.             var result:Array = [];
  21.             var n:int = contour.length
  22.             if ( n <3 ) return null
  23.            
  24.             var verts:Array = [];
  25.            
  26.               /* we want a counter-clockwise polygon in verts */
  27.             var v:int
  28.            
  29.               if ( 0.0 <area(contour) ){
  30.                 for (v=0; v<n; v++) verts[v] = v;
  31.               }else{
  32.                 for(v=0; v<n; v++) verts[v] = (n-1)-v;
  33.               }
  34.            
  35.               var nv:int = n;
  36.            
  37.               /*  remove nv-2 vertsertices, creating 1 triangle every time */
  38.               var count:int = 2*nv;   /* error detection */
  39.              var m:int;
  40.               for(m=0, v=nv-1; nv>2; )
  41.               {
  42.                 /* if we loop, it is probably a non-simple polygon */
  43.                 if (0>= (count--)){
  44.                   //** Triangulate: ERROR - probable bad polygon!
  45.                  // trace("bad poly");
  46.                   return null;
  47.                 }
  48.            
  49.                 /* three consecutive vertices in current polygon, <u,v,w> */
  50.                 var u:int = v; if (nv <= u) u = 0;     /* previous */
  51.                 v = u+1; if (nv <= v) v = 0;     /* new v    */
  52.                 var w:int = v+1; if (nv <= w) w = 0;     /* next     */
  53.            
  54.                 if ( snip(contour,u,v,w,nv,verts)){
  55.                   var a:int,b:int,c:int,s:int,t:int;
  56.            
  57.                   /* true names of the vertices */
  58.                   a = verts[u]; b = verts[v]; c = verts[w];
  59.            
  60.                   /* output Triangle */
  61.                   result.push( contour[a] );
  62.                   result.push( contour[b] );
  63.                   result.push( contour[c] );
  64.            
  65.                   m++;
  66.            
  67.                   /* remove v from remaining polygon */
  68.                   for(s=v,t=v+1;t<nv;s++,t++) verts[s] = verts[t]; nv--;
  69.            
  70.                   /* resest error detection counter */
  71.                   count = 2 * nv;
  72.                 }
  73.               }
  74.            
  75.               return result;
  76.         }
  77.        
  78.         // calculate area of the contour polygon
  79.         public function area(contour:Array):Number{
  80.             var n:int = contour.length;
  81.             var a:Number  = 0.0;
  82.            
  83.             for(var p:int=n-1, q:int=0; q<n; p=q++){
  84.                 a += contour[p].x * contour[q].y - contour[q].x * contour[p].y;
  85.             }
  86.             return a * 0.5;
  87.         }
  88.        
  89.         // see if p is inside triangle abc
  90.         public function insideTriangle(ax:Number, ay:Number, bx:Number, by:Number, cx:Number, cy:Number,px:Number,py:Number):Boolean{
  91.                                                            
  92.               var aX:Number, aY:Number, bX:Number, bY:Number
  93.               var cX:Number, cY:Number, apx:Number, apy:Number;
  94.               var bpx:Number, bpy:Number, cpx:Number, cpy:Number;
  95.               var cCROSSap:Number, bCROSScp:Number, aCROSSbp:Number;
  96.            
  97.               aX = cx - bx;  aY = cy - by;
  98.               bX = ax - cx;  bY = ay - cy;
  99.               cX = bx - ax;  cY = by - ay;
  100.               apx= px  -ax;  apy= py - ay;
  101.               bpx= px - bx;  bpy= py - by;
  102.               cpx= px - cx;  cpy= py - cy;
  103.            
  104.               aCROSSbp = aX*bpy - aY*bpx;
  105.               cCROSSap = cX*apy - cY*apx;
  106.               bCROSScp = bX*cpy - bY*cpx;
  107.            
  108.               return ((aCROSSbp>= 0.0) && (bCROSScp>= 0.0) && (cCROSSap>= 0.0));
  109.         }
  110.        
  111.         private function snip(contour:Array, u:int, v:int, w:int, n:int, verts:Array):Boolean{
  112.               var p:int;
  113.               var ax:Number, ay:Number, bx:Number, by:Number;
  114.               var cx:Number, cy:Number, px:Number, py:Number;
  115.            
  116.                   ax = contour[verts[u]].x;
  117.                   ay = contour[verts[u]].y;
  118.                
  119.                   bx = contour[verts[v]].x;
  120.                   by = contour[verts[v]].y;
  121.                
  122.                   cx = contour[verts[w]].x;
  123.                   cy = contour[verts[w]].y;
  124.            
  125.           if ( EPSILON> (((bx-ax)*(cy-ay)) - ((by-ay)*(cx-ax))) ) return false;
  126.            
  127.               for (p=0;p<n;p++){
  128.                     if( (p == u) || (p == v) || (p == w) ) continue;
  129.                     px = contour[verts[p]].x
  130.                     py = contour[verts[p]].y
  131.                     if (insideTriangle(ax,ay,bx,by,cx,cy,px,py)) return false;
  132.               }
  133.               return true;
  134.         }
  135.     }
  136. }

... and the Pnt class:

Actionscript:
  1. // Point class, no reason to use AS3's build in Point
  2. package{
  3.     public class Pnt {
  4.         public var x:Number;
  5.         public var y:Number;
  6.         public function Pnt(x:Number, y:Number){
  7.             this.x = x;
  8.             this.y = y;
  9.         }
  10.     }
  11. }

I also found a nice description of the basic technique being employed here.

UPDATE:
This should be obvious, but I was targeting fp9 with this... thus the use of Array instead of Vector.

Posted in 3D, Math, graphics algorithms, misc | Tagged , | 6 Comments

Odd Even Classic

Actionscript:
  1. // from http://www.bit-101.com/blog/?p=729
  2. var number:Number = 10.5;
  3.  
  4. // for numbers
  5. var isEven:Boolean = (number % 2) == 0;
  6. trace(isEven);
  7.  
  8. // for ints
  9. var integer:int = 10;
  10. isEven = (integer & 1) == 0;
  11. trace(isEven);

This is a classic that I've seen all over the place online... found myself needing it today and figured I should post it. It just an easy way to determine if a number is odd or even... I remember originally reading it over at Bit-101.com a few years back...

Two posts today because I think I missed a post recently...

Posted in Math, Operators | Tagged , | Leave a comment