Tag Archives: Box2D

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 | Also tagged , , , | 4 Comments

QuickBox2D groupIndex Platforms

Actionscript:
  1. import com.actionsnippet.qbox.*;
  2. import Box2D.Common.Math.*;
  3. import Box2D.Collision.Shapes.*;
  4.  
  5. [SWF(width = 800, height = 600, backgroundColor = 0x000000)]
  6.  
  7. var sim:QuickBox2D = new QuickBox2D(this);
  8.  
  9. sim.createStageWalls();
  10.  
  11. var boxNum:int = 8;
  12. var boxes:Array = [];
  13. var xp:Number, yp:Number, w:Number;
  14. for (var i:int = 0; i<boxNum; i++){
  15.     xp = 3 + Math.random() * 10;
  16.     yp = 4 + i * 2;
  17.     w = 2 + Math.random() * 3;
  18.     boxes.push(sim.addBox({x: xp, y: yp, width: w, height: 0.5, density:0, groupIndex:-1, fillColor:0xFF6532}));
  19. }
  20.  
  21. var char:QuickObject = sim.addBox({x:2, y:18, width:1, height:2, allowSleep:false, groupIndex:-1, fillColor:0x0099CC});
  22.  
  23. sim.start();
  24.  
  25. var charVel:b2Vec2;
  26. var charVelAng:Number;
  27.  
  28. addEventListener(Event.ENTER_FRAME, onLoop);
  29. function onLoop(evt:Event):void {
  30.      
  31.     charVel = char.body.GetLinearVelocity();
  32.     charVelAng =  char.body.GetAngularVelocity();
  33.     var filter:b2FilterData;
  34.    
  35.     if (key[Keyboard.RIGHT]){
  36.         charVel.x += 1
  37.         char.body.SetLinearVelocity(charVel);
  38.         charVelAng += 1;
  39.         char.body.SetAngularVelocity(charVelAng);
  40.     }
  41.     if (key[Keyboard.LEFT]){
  42.         charVel.x -=1;
  43.         char.body.SetLinearVelocity(charVel);
  44.         charVelAng -= 1;
  45.         char.body.SetAngularVelocity(charVelAng);
  46.     }
  47.     if (key[Keyboard.UP] && sim.w.GetContactCount()> 0){
  48.          charVel.y = -10;
  49.          trace(charVel.y);
  50.          char.body.SetLinearVelocity(charVel);
  51.          charVelAng *= 0.8;
  52.          char.body.SetAngularVelocity(charVelAng);
  53.     }
  54.     for (var i:int = 0; i<boxes.length; i++){
  55.         var rect:Rectangle = char.userData.getRect(this);
  56.         if (rect.bottom / 30 <boxes[i].y){
  57.             filter = boxes[i].shape.GetFilterData();
  58.             filter.groupIndex = 1;
  59.             boxes[i].shape.SetFilterData(filter);
  60.         }else{
  61.             filter = boxes[i].shape.GetFilterData();
  62.             if (filter.groupIndex != -1){
  63.                 filter.groupIndex = -1;
  64.                 boxes[i].shape.SetFilterData(filter);
  65.             }
  66.         }
  67.     }
  68. }
  69.  
  70. var key:Object = new Object();
  71. stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyPressed);
  72. stage.addEventListener(KeyboardEvent.KEY_UP, onKeyReleased);
  73. function onKeyPressed(evt:KeyboardEvent):void{ key[evt.keyCode] = true; }
  74. function onKeyReleased(evt:KeyboardEvent):void{ key[evt.keyCode] = false; }

NOTE: This requires the QuickBox2D mini-library

This snippet shows how to use groupIndex to create simple platforms for a character to jump on. A few people have asked me about this so I figured I'd post about it. It works by altering the groupIndex of each platform based on the characters position - if the character is below a platform, both the character and the platform have groupIndex -1 (meaning they will not collide). As soon as the character is above a platform, the platforms groupIndex is set to 1 (allowing the character to walk on the platform despite having just passed through it.


Have a look at the swf...


It's also worth noting that I'm using b2World.GetContactCount() to make sure it's ok to jump... if there were more going on in the demo you'd need to check a specific contact point(s), but since the only collision that could happen involves the character this works nicely...

Posted in Box2D, QuickBox2D | Also tagged , , , | 10 Comments

QuickBox2D Unicycler

Actionscript:
  1. import com.actionsnippet.qbox.*;
  2. import Box2D.Common.Math.*;
  3. import Box2D.Dynamics.Joints.*;
  4. [SWF (backgroundColor=0x000000, width=700, height=600, frameRate=60)]
  5. var sim:QuickBox2D = new QuickBox2D(this, {debug:false,gravityY:10, renderJoints:false});
  6. sim.setDefault({fillColor:0xCC0000,lineAlpha:0});
  7. sim.createStageWalls();
  8.  
  9. for (var i:int = 0; i<20; i++){
  10.     sim.addCircle({x:1+i * 0.8, y:1, radius:0.1+Math.random()*0.1, restitution:0.3});
  11. }
  12.  
  13. sim.setDefault({fillColor:0xEFEFEF, fillAlpha:0.5, lineColor:0xFFFFFF, groupIndex:-2});
  14. var ancA:QuickObject = sim.addCircle({x:20, y:12, radius:0.5, density:0, skin:"none"});
  15. var ancB:QuickObject = sim.addCircle({x:20, y:2, radius:0.5, density:0, skin:"none"});
  16. var head:QuickObject = sim.addCircle({x:0, y:-0.6, radius:0.5});
  17. var neck:QuickObject = sim.addBox({x:0, y:1, width:0.5, height:2});
  18. var spindle:QuickObject = sim.addBox({x:0, y:3, width:0.1, height:2})
  19. spindle.userData.visible = false;
  20. var top:QuickObject = sim.addGroup({objects:[head, neck, spindle], x:10, y:5, fixedRotation:true});
  21. var upperLegA:QuickObject = sim.addBox({x:10, y:7.5, width:0.25, height:1.5});
  22. var lowerLegA:QuickObject = sim.addBox({x:10, y:9, width:0.25, height:1.5});
  23. var wheel:QuickObject = sim.addCircle({x:10, y:9, radius:1});
  24. var upperLegB:QuickObject = sim.addBox({x:10, y:7.5, width:0.25, height:1.5});
  25. var lowerLegB:QuickObject = sim.addBox({x:10, y:9, width:0.25, height:1.5});
  26. var upperArmA:QuickObject = sim.addBox({x:10.7, y:5.25, width:1.5, height:0.25});
  27. var lowerArmA:QuickObject = sim.addBox({x:11.8, y:5.25, width:1.2, height:0.25});
  28. var upperArmB:QuickObject = sim.addBox({x:9.5, y:5.25, width:1.5, height:0.25});
  29. var lowerArmB:QuickObject = sim.addBox({x:8.4, y:5.25, width:1.2, height:0.25});
  30. var anchor:b2Vec2 = new b2Vec2();
  31. function connect(a:QuickObject, b:QuickObject, lower:Number, upper:Number, offX:Number=0, offY:Number = 0):QuickObject{
  32.      var min:Number = Math.min(a.y, b.y);
  33.      var max:Number = Math.max(a.y, b.y);
  34.      anchor.y = min + (max - min) * 0.5 + offY;
  35.      min = Math.min(a.x, b.x);
  36.      max = Math.max(a.x, b.x);
  37.      anchor.x = min + (max - min) * 0.5 + offX;
  38.      return sim.addJoint({type:"revolute", a:a.body, b:b.body, x1:anchor.x, y1:anchor.y, lowerAngle:lower, upperAngle:upper});
  39. }
  40. sim.addJoint({type:"revolute", a:wheel.body, b:top.body, x1:wheel.x, y1:wheel.y});
  41. sim.addJoint({type:"revolute", a:lowerLegA.body, b:wheel.body, x1:lowerLegA.x, y1:lowerLegA.y + 0.7});
  42. sim.setDefault({enableLimit:true});
  43. connect(top, upperArmA, 0, 3, -.3, .1);
  44. connect(upperArmA, lowerArmA, -2.5, -1, 0, 0);
  45. connect(top, upperArmB, -3, 0, .3, .1);
  46. connect(upperArmB, lowerArmB, -2.5, -1, 0, 0);
  47. sim.addJoint({type:"distance", a:lowerArmA.body, b:ancA.body, frequencyHz:0.3});
  48. sim.addJoint({type:"distance", a:lowerArmB.body, b:ancB.body, frequencyHz:0.3});
  49. sim.setDefault({enableLimit:true});
  50. connect(top, upperLegA, -6.28, 6, 0, 0.8);
  51. connect(upperLegA, lowerLegA, .1, 6);
  52. wheel.angle = Math.PI;
  53. connect(top, upperLegB, -6.28, 6, 0, 0.8);
  54. connect(upperLegB, lowerLegB, .1, 6);
  55. sim.setDefault({enableLimit:false, type:"revolute"});
  56. sim.addJoint({a:lowerLegB.body, b:wheel.body, x1:lowerLegB.x, y1:lowerLegB.y + 0.7});
  57.  
  58. sim.start();
  59. sim.mouseDrag();
  60.  
  61. var sd:Number = 5, s:Number = 0, t:Number = 0;
  62. addEventListener(Event.ENTER_FRAME, function():void{
  63.     top.angle = Math.cos(t += 0.05) * 0.2;
  64.     if (top.x> 19) sd = -5
  65.     if (top.x <5) sd = 5;
  66.     s += (sd - s) / 8;
  67.     wheel.body.SetAngularVelocity(s);
  68. });

This chunk of code uses QuickBox2D to create a simple looking character riding a unicycle...

Have a look at the swf...

Posted in Box2D, QuickBox2D, motion | Also tagged , , , | 9 Comments

QuickBox2D Floating Walker

Actionscript:
  1. import com.actionsnippet.qbox.*;
  2. import Box2D.Common.Math.*;
  3. import Box2D.Dynamics.Joints.*;
  4.  
  5. [SWF (backgroundColor=0x000000, width=700, height=600, frameRate=60)]
  6.  
  7. var sim:QuickBox2D = new QuickBox2D(this, {gravityY:.2});
  8.  
  9. sim.setDefault({fillColor:0xEFEFEF, fillAlpha:0.5, lineColor:0xFFFFFF});
  10.  
  11. sim.createStageWalls();
  12.  
  13. for (var i:int = 0; i<20; i++){
  14.     sim.addCircle({x:1+i, y:1, radius:0.2, restitution:1});
  15. }
  16.  
  17. var head:QuickObject = sim.addCircle({x:0, y:0, radius:0.5});
  18. var neck:QuickObject = sim.addBox({x:0, y:1, width:0.5, height:2});
  19. var top:QuickObject = sim.addGroup({objects:[head, neck], x:10, y:5, fixedRotation:true});
  20.  
  21. var upperLegA:QuickObject = sim.addBox({x:10, y:7.5, width:0.25, height:1.5,groupIndex:-2});
  22. var lowerLegA:QuickObject = sim.addBox({x:10, y:9, width:0.25, height:1.5,groupIndex:-2});
  23.  
  24. var upperLegB:QuickObject = sim.addBox({x:10, y:7.5, width:0.25, height:1.5,groupIndex:-2});
  25. var lowerLegB:QuickObject = sim.addBox({x:10, y:9, width:0.25, height:1.5,groupIndex:-2});
  26.  
  27. var anchor:b2Vec2 = new b2Vec2();
  28. function connect(a:QuickObject, b:QuickObject, lower:Number, upper:Number, offX:Number=0, offY:Number = 0):QuickObject{
  29.      var min:Number = Math.min(a.y, b.y);
  30.      var max:Number = Math.max(a.y, b.y);
  31.      anchor.y = min + (max - min) * 0.5 + offY;
  32.      min = Math.min(a.x, b.x);
  33.      max = Math.max(a.x, b.x);
  34.      anchor.x = min + (max - min) * 0.5 + offX;
  35.      return sim.addJoint({a:a.body, b:b.body, x1:anchor.x, y1:anchor.y, lowerAngle:lower, upperAngle:upper});
  36. }
  37.  
  38. sim.setDefault({type:"revolute", collideConnected:false, enableLimit:true, enableMotor:true, maxMotorTorque:250, lineColor:0xFFFFFF});
  39.  
  40. var upperLegAJoint:QuickObject = connect(top, upperLegA, -1, 1, 0, 0.8);
  41. var upperLegBJoint:QuickObject = connect(top, upperLegB, -1, 1, 0, 0.8);
  42.  
  43. var lowerLegAJoint:QuickObject = connect(upperLegA, lowerLegA, -1, 1);
  44. var lowerLegBJoint:QuickObject = connect(upperLegB, lowerLegB, -1, 1);
  45.  
  46. sim.start();
  47. sim.mouseDrag();
  48.  
  49.  
  50. var j:b2RevoluteJoint;
  51. var t:Number = -Math.PI * 0.5;
  52. addEventListener(Event.ENTER_FRAME, onLoop);
  53. function onLoop(evt:Event):void {
  54.    
  55.     var s1:Number = 1*Math.sin(t);
  56.     var s2:Number = 1*Math.sin(t+Math.PI);
  57.     t+= 0.05;
  58.    
  59.     top.body.SetAngularVelocity(s1 * 0.25);
  60.    
  61.     j =  upperLegAJoint.joint as b2RevoluteJoint;
  62.     j.SetMotorSpeed(s1);
  63.    
  64.     j =  upperLegBJoint.joint as b2RevoluteJoint;
  65.     j.SetMotorSpeed(s2);
  66.      
  67.     j = lowerLegAJoint.joint as b2RevoluteJoint;
  68.     j.SetMotorSpeed(-s2);
  69.    
  70.     j = lowerLegBJoint.joint as b2RevoluteJoint;
  71.     j.SetMotorSpeed(-s1);
  72. }

Experimenting with primitive robot designs... this was just an improvised design - it looks like it may make sense to break out a pencil and some paper - or my wacom... to get something interesting...


Have a look at the swf...


Posted in Box2D, QuickBox2D, motion | Also tagged , , , | 1 Comment