Motor2 – Fluid On the Brain

June 6th, 2008

While working with Box2D I came across another engine based on it called Motor2. Its creator Michael Baczynski is working on some amazing additions. What I want to see happen more then anything else is the buoyancy simulation. It makes me drool.

Bookmark and Share

Multi-touch Holly Grail, 60fps

June 4th, 2008

Having been involved in DIY multi-touch for over a year now I am still shocked that the 60fps barrier stands. I can’t really complain because I am not a C++ programmer which prevents me from doing it myself but it’s still surprising. Most of the demos of home brew multi-touch displays get slammed for their lag from the arm chair critics. Part of the problem is touchlib, the blob tracker most of the DIY multi-touch community is using. Don’t get me wrong without touchlib most of us wouldn’t have working multi-touch setups. But it does have some serious stability issues, no binary socket support (not an issue if your not a flash developer) and no support for 60fps. Granted not everyone has a firefly MV or similar camera which shots 60fps but it can’t be that hard to integrate a native driver.

But this isn’t a post just to rant. I have decided to start the process of building a new and robust blob tracker that can shoot at 60fps. Below are the first screen shots and some processing times. Lots more to come. Post a comment if you are interested in knowing more.

Bookmark and Share

Creating Complex Shapes in Box2D UPDATED

June 2nd, 2008

Creating complex shapes,aka compound shapes, in Box2d is accomplished by adding multiple shapes to a body. In exploring complex shapes I learned a bunch about defining objects in general. Again I couldn’t find any tutorials on this but I have been using the box2d manual. It helps but isn’t the best.

Before we start
When I started to experiment with box2d I discounted the importance/utility of the debug draw mode. It doesn’t really do anything other then show you what is in the box2d world, which when your understanding of positioning is still bad helps a ton. So turn it on, it’s magic. If you change the m_drawScale to 1 you can use pixels as your units. Include the following after you create the b2World.

m_sprite = new Sprite();
addChild(m_sprite);
var dbgDraw:b2DebugDraw = new b2DebugDraw();
var dbgSprite:Sprite = new Sprite();
m_sprite.addChild(dbgSprite);
dbgDraw.m_sprite = m_sprite;
dbgDraw.m_drawScale = 1;
dbgDraw.m_fillAlpha = 0.3;
dbgDraw.m_lineThickness = 1.0;
dbgDraw.m_drawFlags = b2DebugDraw.e_shapeBit | b2DebugDraw.e_jointBit;
m_world.SetDebugDraw(dbgDraw);

Complex shapes need a body
Ok onto complex shapes. When creating any object in box2d you start by creating a b2BodyDef. The b2BodyDef defines the intial properties of a b2Body object. When you create a b2Body it will either be a static (not moving) or a dynamic (moving) object. It also provides the container for shape definitions and custom visuals . b2Body creation example:

//Create a new body definition without any shapes
var bodyDef:b2BodyDef = new b2BodyDef();
//Set its position in the world. Units in meters.
bodyDef.position.Set(150, 150);
//Create a dynamic body in the world from the bodyDef
var body:b2Body = m_world.CreateDynamicBody(bodyDef);

Creating shapes and adding them to the body
After creating the body, we need to define and add some shapes to it. There are 2 basic types of shapes, circles (b2CircleDef) and polygons (b2PolygonDef). Both of these inherit from the b2ShapeDef class which is where you will find most of the editable shape properties (friction, restitution, density, etc). When creating shapes everything is relative to a centered registration point. b2PolygonDef shapes can be defined either using SetAsBox, for squares, or via a vertex array. In the documentation it says to limit to 8 vertex points for any polygon and it has to be convex. Box2DFlash differs a little from the C++ version when creating square polygons. To position a square poly in the body you use SetAsOrientedBox instead of SetAsBox. SetAsOrientedBox takes two extra parameters for position (b2Vec2) and angle (in radians). If you create a shape using vertex points you don’t need to use SetAsBox or SetAsOrientedBox because you have defined all the points manually. Shape creation example:

//Create a single rectangular poylgon
var poly1:b2PolygonDef = new b2PolygonDef();
//Make a 120px by 50px poly that will be centered on the body centered and without any angle
poly1.SetAsOrientedBox(60, 30, new b2Vec2(0, 0), 0);
//Give it some friction. 0 being none 1 being a lot
poly1.friction = 0.3;
//Give it some density which will be used to calculate mass later
poly1.density = 1;
//Restitution is how elastic something is 0 being in elastic and 1 being totally elastic
poly1.restitution = .1;

Putting it all together
Combining the two objects is really easy. Call the CreateShape() method of the b2Body with the shape as an argument. If you are going to add more shapes to the body you can just call CreateShape() again. Example:

//Add the poly1 shape to the body
body.CreateShape(poly1);
//If you were going to add more its as simple as
//body.CreateShape(poly2)
//SetMassFromShapes is a great feature of Box2D. It will analyze your body and determine the mass and center of gravity from the shapes.
body.SetMassFromShapes();

Complete Example Source

/*
Original software provided by Erin Catto http://www.gphysics.com. Thanks Erin for all the hard work.
Also thanks to Matthew Bush for all the hard work in porting box2D to flash
Some of the code in this example is from the Box2D Test bed examples. Check them out they are really helpful.
*/
package {

	import flash.display.*;
	import flash.events.*;
	import flash.text.*;
	import flash.geom.*;

	import Box2D.Dynamics.*;
	import Box2D.Collision.*;
	import Box2D.Collision.Shapes.*;
	import Box2D.Dynamics.Joints.*;
	import Box2D.Dynamics.Contacts.*;
	import Box2D.Common.*;
	import Box2D.Common.Math.*;
	
	public class ComplexTest extends Sprite {
		private var m_world:b2World;
		private var m_iterations:int = 10;
		private var m_timeStep:Number = 1/30;
		private var m_sprite:Sprite;
		//Convert to rads from degrees
		private var dtor:Number = Math.PI/180;

		public function ComplexTest():void {
			this.addEventListener(Event.ENTER_FRAME, update, false, 0, true);
			// Creat world AABB
			var worldAABB:b2AABB = new b2AABB();
			worldAABB.lowerBound.Set(-3000, -3000);
			worldAABB.upperBound.Set(3000, 3000);

			// Define the gravity vector
			var gravity:b2Vec2 = new b2Vec2(0, 300);

			// Allow bodies to sleep
			var doSleep:Boolean = true;

			// Construct a world object
			m_world = new b2World(worldAABB, gravity, doSleep);
			m_sprite = new Sprite();
			addChild(m_sprite);
			var dbgDraw:b2DebugDraw = new b2DebugDraw();
			var dbgSprite:Sprite = new Sprite();
			m_sprite.addChild(dbgSprite);
			dbgDraw.m_sprite = m_sprite;
			dbgDraw.m_drawScale = 1;
			dbgDraw.m_fillAlpha = .3;
			dbgDraw.m_lineThickness = 1;
			dbgDraw.m_drawFlags = b2DebugDraw.e_shapeBit | b2DebugDraw.e_jointBit;
			m_world.SetDebugDraw(dbgDraw);

			// Add ground body
			var ground:b2BodyDef = new b2BodyDef();
			ground.position.Set(0, stage.stageHeight);

			//Define a ground poly
			var groundPoly:b2PolygonDef = new b2PolygonDef();
			groundPoly.SetAsBox(1000, 90);
			groundPoly.friction = .3;

			var groundBody:b2Body = m_world.CreateStaticBody(ground);
			groundBody.CreateShape(groundPoly);
			groundBody.SetMassFromShapes();

			//Create a new body definition without any shapes
			var bodyDef:b2BodyDef = new b2BodyDef();
			//Set its position in the world. Units in meters.
			bodyDef.position.Set(150, 150);
			//Give a bit of an angle to show the object colliding
			bodyDef.angle = 15 * dtor;
			//Create a dynamic body in the world from the bodyDef
			var body:b2Body = m_world.CreateDynamicBody(bodyDef);


			//Create a single rectangular poylgon
			var poly1:b2PolygonDef = new b2PolygonDef();
			//Make a 4m by 2m poly that will be centered on the body centered and without any angle
			poly1.SetAsOrientedBox(60, 30, new b2Vec2(0, 0), 0);
			//Give it some friction. 0 being none 1 being a lot
			poly1.friction = .3;
			//Give it some density which will be used to calculate mass later
			poly1.density = 1;
			//Restitution is how elastic something is 0 being in elastic and 1 being totally elastic
			poly1.restitution = .1;

			//Create a second poly
			var poly2:b2PolygonDef = new b2PolygonDef();
			poly2.SetAsOrientedBox(30, 60, new b2Vec2(30, 0), 0);
			poly2.friction = .3;
			poly2.density = 1;
			poly2.restitution = .1;

			body.CreateShape(poly1);
			body.CreateShape(poly2);
			body.SetMassFromShapes();
		}
		
		private function update(e:Event):void {
			m_world.Step(m_timeStep, m_iterations);
			// Go through body list and update sprite positions/rotations
			var bb:b2Body = m_world.m_bodyList;
			for (bb; bb; bb = bb.m_next) {

				if (bb.m_userData is Sprite) {
					bb.m_userData.x = bb.GetPosition().x;
					bb.m_userData.y = bb.GetPosition().y;
					bb.m_userData.rotation = bb.GetAngle() * (180/Math.PI);
				}
			}
		}
	}
}
Bookmark and Share

Intro to Box2D in Flash, Visual Explination UPDATED

May 27th, 2008

Getting started with Box2D in Flash is harder then it should be. The demos are great and if you spend some time with them and the Box2D forums you can get up and running pretty quick. It’s a shame there isn’t more tutorials yet. I hope this intro will help get people started a bit quicker. I will post more as I do more with it.

Units
Units in the Box2D examples seem strange at first until you find out the secret. They are use the units from the C++ package which measured things in meters. They are making a meter = 30px in flash. If you just change the m_drawScale of the debug draw to 1 everything will be in pixels

SetAsBox()
Everything in Box2D is setup with a centered registration point. SetAsBox() through me off at first because I was expecting it to take the full width and height of the box as parameters but it actually takes half the width and height. See diagram below.

That’s it for now. Next up will be setting center of gravity, friction, restitution, etc.

Bookmark and Share

Regular Expressions In Flash

May 14th, 2008

Flash CS3’s addition of regular expressions gives you tons of control over your text in flash. For anyone who has experience with regexp this will seem trivial but for those just starting out I hope this example will prove useful. The example is for processing specific data out of an HTML page because there isn’t a REST service for this data.
First, you pull in the HTML document using URLLoader. The data of the URLLoader will be treated as plain text making it perfect to process with a RegExp.

//Create a request for the weather page
var myURLRequest:URLRequest = new URLRequest("http://www.weatheroffice.gc.ca/marine/marine_e.html?46146");
//Load the weather page into a urlloader object.
var myURLLoader:URLLoader = new URLLoader(myURLRequest);
//Listen for the load complete event for the URLLoader object
myURLLoader.addEventListener(Event.COMPLETE,weatherLoadComplete);

Now that the HTML file is in flash we can write a regexp to find specific data. Creating named groups within your regexp was new to me and an easy way to access specific data later on.

//Create a regexp literal that will pull out the just the air temperature from the web page
var weatherPattern:RegExp = /Temperature<BR>.*<strong>(?P<airtemp>.*)°C<\/strong>/;

The next step is to run that regexp against the text document. If a match is found you can access the whole string of the match or just the named group.

//Load complete event handler that traces out the regular expression data
function weatherLoadComplete(e:Event):void{
    //Execute the pattern against the text document returning an object containing a match
    var match:Object = weatherPattern.exec(e.target.data);
    //Since exec returns an object this will can use the full match
    trace(match);
    //Or just the group
    trace(match.airtemp);
}

Complete source.

//Create a request for the weather page
var myURLRequest:URLRequest = new URLRequest("http://www.weatheroffice.gc.ca/marine/marine_e.html?46146");
//Load the weather page into a urlloader object.
var myURLLoader:URLLoader = new URLLoader(myURLRequest);
//Listen for the load complete event for the URLLoader object
myURLLoader.addEventListener(Event.COMPLETE,weatherLoadComplete);
//Create a regexp literal that will pull out the just the air temperature from the web page
var weatherPattern:RegExp = /Temperature<BR>.*<strong>(?P<airtemp>.*)°C<\/strong>/;
//Load complete event handler that traces out the regular expression data
function weatherLoadComplete(e:Event):void{
    //Execute the pattern against the text document returning an object containing a match.
    var match:Object = weatherPattern.exec(e.target.data);
    //Since exec returns an object this will can use the full match
    trace(match);
    //Or just the group
    trace(match.airtemp);
}
Bookmark and Share