API Docs for: 0.1.0
Show:

File: src/zerk/class/game/engine/system/physics/box2d.js

/*
 * TODO Give the Box2dWeb related properties their real types 
 */
/**
 * Box2D Physics System
 * 
 * Box2dWeb implementation.
 * 
 * @class box2d
 * @namespace zerk.game.engine.system.physics
 * @extends zerk.game.engine.system.physics
 * @module zerk
 **/
zerk.define({
	
	name: 'zerk.game.engine.system.physics.box2d',
	extend: 'zerk.game.engine.system.physics'
	
},{
	
	/**
	 * Physics configuration
	 * 
	 * @property _config
	 * @type Object 
	 * @protected
	 */
	_config: null,
	
	/**
	 * Box2D world
	 * 
	 * @property _world
	 * @type Box2D.Dynamics.b2World
	 * @protected
	 */
	_world: null,
	
	/**
	 * Handle for the mouse joint
	 * 
	 * @property _mouseJoint
	 * @type Object
	 * @protected
	 */
	_mouseJoint: null,
	
	/**
	 * Stores a vector for the mouse joint function
	 * 
	 * @property _mouseJointVec
	 * @type Object
	 * @protected
	 */
	_mouseJointVec: null,
	
	/**
	 * Stores the last selected body
	 * 
	 * @property _selectedBody
	 * @type Object
	 * @protected
	 */
	_selectedBody: null,
	
	/**
	 * List of bodies to be destroyed after current simulation tick
	 * 
	 * @property _destroyBodyList
	 * @type Array
	 * @protected
	 */
	_destroyBodyList: null,
	
	/**
	 * List of joints to be destroyed after current simulation tick
	 * 
	 * @property __destroyJointList
	 * @type Array
	 * @protected
	 */
	_destroyJointList: null,
	
	/**
	 * Shortcut for Box2D.Common.Math.b2Vec2
	 * 
	 * @property _b2Vec2
	 * @type Object
	 * @protected
	 */
	_b2Vec2: Box2D.Common.Math.b2Vec2,
	
	/**
	 * Shortcut for Box2D.Collision.b2AABB
	 * 
	 * @property _b2AABB
	 * @type Object
	 * @protected
	 */
	_b2AABB: Box2D.Collision.b2AABB,
	
	/**
	 * Shortcut for Box2D.Dynamics.b2BodyDef
	 * 
	 * @property _b2BodyDef
	 * @type Object
	 * @protected
	 */
	_b2BodyDef: Box2D.Dynamics.b2BodyDef,
	
	/**
	 * Shortcut for Box2D.Dynamics.b2Body
	 * 
	 * @property _b2Body
	 * @type Object
	 * @protected
	 */
	_b2Body: Box2D.Dynamics.b2Body,
	
	/**
	 * Shortcut for Box2D.Dynamics.b2FixtureDef
	 * 
	 * @property _b2FixtureDef
	 * @type Object
	 * @protected
	 */
	_b2FixtureDef: Box2D.Dynamics.b2FixtureDef,
	
	/**
	 * Shortcut for Box2D.Dynamics.b2World
	 * 
	 * @property _b2World
	 * @type Object
	 * @protected
	 */
	_b2World: Box2D.Dynamics.b2World,
	
	/**
	 * Shortcut for Box2D.Collision.Shapes.b2PolygonShape
	 * 
	 * @property _b2PolygonShape
	 * @type Object
	 * @protected
	 */
	_b2PolygonShape: Box2D.Collision.Shapes.b2PolygonShape,
	
	/**
	 * Shortcut for Box2D.Collision.Shapes.b2CircleShape
	 * 
	 * @property _b2CircleShape
	 * @type Object
	 * @protected
	 */
	_b2CircleShape: Box2D.Collision.Shapes.b2CircleShape,
	
	/**
	 * Shortcut for Box2D.Dynamics.b2DebugDraw
	 * 
	 * @property _b2DebugDraw
	 * @type Object
	 * @protected
	 */
	_b2DebugDraw: Box2D.Dynamics.b2DebugDraw,
	
	/**
	 * Shortcut for Box2D.Dynamics.Joints.b2MouseJointDef
	 * 
	 * @property _b2MouseJointDef
	 * @type Object
	 * @protected
	 */
	_b2MouseJointDef: Box2D.Dynamics.Joints.b2MouseJointDef,
	
	/**
	 * Shortcut for Box2D.Dynamics.Joints.b2RevoluteJointDef
	 * 
	 * @property _b2RevoluteJointDef
	 * @type Object
	 * @protected
	 */
	_b2RevoluteJointDef: Box2D.Dynamics.Joints.b2RevoluteJointDef,
	
	/**
	 * Shortcut for Box2D.Dynamics.Joints.b2DistanceJointDef
	 * 
	 * @property _b2DistanceJointDef
	 * @type Object
	 * @protected
	 */
	_b2DistanceJointDef: Box2D.Dynamics.Joints.b2DistanceJointDef,
	
	/**
	 * Shortcut for Box2D.Dynamics.b2ContactListener
	 * 
	 * @property _b2ContactListener
	 * @type Object
	 * @protected
	 */
	_b2ContactListener: Box2D.Dynamics.b2ContactListener,
	
	/**
	 * Class constructor
	 * 
	 * @method init
	 * @param {zerk.game.engine} engine Game engine
	 */
	init: function(engine,config) {
		
		zerk.parent('zerk.game.engine.system.physics.box2d').init.apply(
			this,
			arguments
		);
		
		this._destroyBodyList=[];
			
		this._destroyJointList=[];
		
		this._world=new this._b2World(
			new this._b2Vec2(
				this._config.gravityX,
				this._config.gravityY
			), // Setup gravity
			true // allow sleep
		);
		
		// Box2D debug draw
		
		if (this._config.debugDraw) {
			
			this.canvas=this._getSystem('viewport').getCanvasPhysicsDebug();
			
			/*
			 * TODO Sync the view position with the game viewport
			 * 
			 * this.canvas.getContext("2d").translate(200,200);
			 */
			
			var debugDraw = new this._b2DebugDraw();
			debugDraw.SetSprite(this.canvas.getContext("2d"));
			debugDraw.SetDrawScale(30.0);
			debugDraw.SetFillAlpha(0.5);
			debugDraw.SetLineThickness(1.0);
			debugDraw.SetFlags(
				this._b2DebugDraw.e_shapeBit | this._b2DebugDraw.e_jointBit
			);
			
			this._world.SetDebugDraw(debugDraw);
			
		}
		
		this._addContactListener();
		
		this._log('Ready');
		
	},
	
	/**
	 * Physics engine tick
	 * 
	 * @method tick
	 */
	_tick: function() {
		
		this._processMouseJoint();
		
		/*
		 * TODO Make world step settings configurable
		 */
		
		// World step 
		this._world.Step(
			1/60, // Frame rate
			10, // Velocity iterations
			10 // Position iterations
		);
		
		if (this._config.debugDraw) {
			this._world.DrawDebugData();
		}
		
		this._world.ClearForces();
		
		this._cleanup();
		
	},
	
	getBody: function(entity,key) {
		
		return entity.components.physics.bodies[key];
		
	},
	
	/**
	 * Applies an impulse to given body
	 * 
	 * @method _bodyApplyImpulse
	 * @param {String} bodyKey
	 * @param {Integer} degrees
	 * @param {Integer} power
	 * @protected
	 */
	bodyApplyImpulse: function(entity,bodyKey,degrees,power) {
		
		var physicsBody=entity.components.physics.bodies[bodyKey]._physicsHandle;
		
		physicsBody.ApplyImpulse(
			new this._b2Vec2(
				Math.cos(degrees*(Math.PI/180))*power,
				Math.sin(degrees*(Math.PI/180))*power
			),
			physicsBody.GetWorldCenter()
		);
		
	},
	
	/**
	 * Sets the linear velocity of given body
	 * 
	 * @method __setLinearVelocity
	 * @param {String} bodyKey
	 * @param {Integer} degrees
	 * @param {Integer} power
	 * @protected
	 */
	setLinearVelocity: function(entity,bodyKey,degrees,power) {
		
		var physicsBody=entity.components.physics.bodies[bodyKey]._physicsHandle;
		
		physicsBody.SetLinearVelocity(
			new this._b2Vec2(
				Math.cos(degrees*(Math.PI/180))*power,
				Math.sin(degrees*(Math.PI/180))*power
			)
		);
		
	},
	
	/**
	 * Sets the position of given body
	 * 
	 * @method _setBodyPosition
	 * @param {String} bodyKey
	 * @param {Object} position
	 * @protected
	 */
	setBodyPosition: function(entity,bodyKey,position) {
		
		var physicsBody=entity.components.physics.bodies[bodyKey]._physicsHandle;
		
		return physicsBody.SetPosition(position);
		
	},
	
	/**
	 * Sets whether given body is allowed to sleep
	 * 
	 * @method _setBodySleepingAllowed
	 * @param {String} bodyKey
	 * @param {Boolean} allowed
	 * @protected
	 */
	setBodySleepingAllowed: function(entity,bodyKey,allowed) {
		
		entity.components.physics.bodies[bodyKey]._physicsHandle
			.SetSleepingAllowed(allowed);
		
	},
	
	/**
	 * Sets whether given body is moveable
	 * 
	 * @method _setBodyMoveable
	 * @param {String} bodyKey
	 * @param {Boolean} moveable
	 * @protected
	 */
	setBodyMoveable: function(entity,bodyKey,moveable) {
		
		var type=((moveable)
			? this._b2Body.b2_dynamicBody
			: this._b2Body.b2_staticBody);
		
		entity.components.physics.bodies[bodyKey]._physicsHandle.SetType(
			type
		);
		
	},
	
	/**
	 * Sets given body to be kinematic
	 * 
	 * @method __setBodyKinematic
	 * @param {String} bodyKey
	 * @protected
	 */
	setBodyKinematic: function(entity,bodyKey) {
		
		entity.components.physics.bodies[bodyKey]._physicsHandle.SetType(
			this._b2Body.b2_kinematicBody
		);
		
	},
	
	
	isBodyActive: function(body) {
		
		return (
			body._physicsHandle.IsActive()==true
		);
		
	},
	
	isBodyAwake: function(body) {
		
		return (
			body._physicsHandle.IsAwake()==true
		);
		
	},
	
	isBodyStatic: function(body) {
		
		return (
			body._physicsHandle.GetType()==this._b2Body.b2_staticBody
		);
		
	},
	
	isBodyKinematic: function(body) {
		
		return (
			body._physicsHandle.GetType()==this._b2Body.b2_kinematicBody
		);
		
	},
	
	
	
	
	/**
	 * Returns position of given body
	 * 
	 * @method _getBodyPosition
	 * @param {String} bodyKey
	 * @return {Object} Position
	 * @protected
	 */
	getBodyPosition: function(entity,bodyKey) {
		
		entity.components.physics.bodies[bodyKey]._physicsHandle.GetPosition();
		
	},
	
	/**
	 * Returns the linear velocity of given body
	 * 
	 * @method _getBodyLinearVelocity
	 * @param {String} bodyKey
	 * @return {Object}
	 * @protected
	 */
	getBodyLinearVelocity: function(entity,bodyKey) {
		
		var physicsBody=entity.components.physics.bodies[bodyKey]._physicsHandle;
		
		return physicsBody.GetLinearVelocity();
		
	},
	
	/**
	 * Destroys given body
	 * 
	 * @method _destroyBody
	 * @param {String} bodyKey
	 * @protected
	 */
	destroyBody: function(entity,bodyKey) {
		
		// Detroy the physics body
		this._scheduleDestroyBody(
			entity.components.physics.bodies[bodyKey]._physicsHandle
		);
		
		// Delete the body 
		delete entity.components.physics.bodies[bodyKey];
		
		// Delete the bodyList entry
		var found=false;
		
		for (var i=0;i<entity.components.physics._bodyList.length;i++) {
			
			if (entity.components.physics._bodyList[i].key==bodyKey) {
				found=true;
				break;
			}
			
		}
		
		if (!found) return;
		
		entity.components.physics._bodyList.splice(i,1);
		
		return true;
		
	},
	
	/**
	 * Destroy bodies and joints schedules to be removed from the world
	 * 
	 * @method _cleanup
	 * @protected
	 */
	_cleanup: function() {
		
		for (var i=0;i<this._destroyJointList.length;i++) {
			
			this._destroyJoint(this._destroyJointList[i]);
			this._destroyJointList[i]=null;
			
		}
		
		this._destroyJointList=[];
		
		for (var i=0;i<this._destroyBodyList.length;i++) {
			
			this._destroyBody(this._destroyBodyList[i]);
			this._destroyBody[i]=null;
			
		}
		
		this._destroyBodyList=[];
		
	},
	
	/**
	 * Schedules a body to be destroyed after current simulation tick
	 * 
	 * @method _scheduleDestroyBody
	 * @param {zerk.game.engine.entity} entity
	 * @param {zerk.game.engine.system.physics.box2d.body} body
	 */
	_scheduleDestroyBody: function(physicsHandle) {
		
		this._destroyBodyList.push(physicsHandle);
		
	},
	
	/**
	 * Schedules a join to be destroyed after current simulation tick
	 * 
	 * @method _scheduleDestroyJoint
	 * @param {zerk.game.engine.entity} entity
	 * @param {zerk.game.engine.system.physics.box2d.join} body
	 */
	_scheduleDestroyJoint: function(physicsHandle) {
		
		this._destroyJointList.push(physicsHandle);
		
	},
	
	/**
	 * Destroys a body
	 * 
	 * @method _destroyBody
	 * @param {zerk.game.engine.entity} entity Entity
	 * @param {zerk.game.engine.system.physics.box2d.body} body Body
	 * @protected
	 */
	_destroyBody: function(physicsHandle) {
		
		if (this._world.IsLocked()) {
			
			console.error('Cannot destroy body, world is locked');
			
		}
		
		this._world.DestroyBody(physicsHandle);
		
	},
	
	/**
	 * Destroys a joint
	 * 
	 * @method _destroyJoint
	 * @param {zerk.game.engine.entity} entity Entity
	 * @param {zerk.game.engine.system.physics.box2d.joint} joint Joint
	 * @protected
	 */
	_destroyJoint: function(physicsHandle) {

		if (this._world.IsLocked()) {
			
			console.error('Cannot destroy joint, world is locked');
			
		}
		
		this._world.DestroyJoint(physicsHandle);
		
	},
	
	/**
	 * Returns body at current cursor position if present
	 * 
	 * @method getBodyAtMouse
	 * @return {Object} Box2D body
	 */
	getBodyAtMouse: function() {
		
		/*
		 * TODO Try to remove dependency to control here
		 */
		var systemControl=this._getSystem('control');
		
		this._mouseJointVec=new this._b2Vec2(
			systemControl.mouse.mouseX,
			systemControl.mouse.mouseY
		);
		
		var aabb=new this._b2AABB();
		
		aabb.lowerBound.Set(
			systemControl.mouse.mouseX-0.001,
			systemControl.mouse.mouseY-0.001
		);
		
		aabb.upperBound.Set(
			systemControl.mouse.mouseX+0.001,
			systemControl.mouse.mouseY+0.001
		);
		
		this._selectedBody=null;
		
		this._world.QueryAABB(this._getBodyAtMouseCallback,aabb);
		
		return this._selectedBody;
		
	},
	
	/**
	 * Returns an array of entities inside given area
	 * 
	 * @method getEntitiesInArea
	 * @param {Float} x1
	 * @param {Float} y1
	 * @param {Float} x2
	 * @param {Float} y2
	 * @return {Array} Entities inside given area
	 */
	getEntitiesInArea: function(x1,y1,x2,y2) {
		
		var aabb=new this._b2AABB();
		
		aabb.lowerBound.Set(x1,y1);
		aabb.upperBound.Set(x2,y2);
		
		var entitiesById={};
		
		this._world.QueryAABB(
			function (fixture) {
				
				var entity=fixture.GetBody().GetUserData().entity;
				
				if (typeof entitiesById[entity.id]
				=='undefined') {
					
					entitiesById[entity.id]=entity;
					
				}
				
				return true;
				
			},
			aabb
		);
		
		var result=[];
		
		for (var id in entitiesById) {
			
			if (this._engine.getEntityById(id)!=null) {
				
				result.push(entitiesById[id]);
				
			}
			
		}
		
		return result;
	},
	
	/**
	 * Dumps elements currently contained in physics simulation to console
	 * 
	 * @method dumpPhysicsData
	 */
	dumpPhysicsData: function() {
		
		var body=this._world.GetBodyList();
		
		console.log('--- Elements in physics simulation ---');
		
		while (body!=null) {
			
			var zerkBody=body.GetUserData();
			
			if (zerkBody) {
				
				console.log('BODY: '+zerkBody._entity.config.id);
				
			} else {
				
				console.log('UNKNOWN BODY',body);
				
			}
			
			body=body.GetNext();
			
		}
		
	},
	
	/**
	 * Synchronize the physic simulation properties of an entity
	 * 
	 * @method syncEntityPhysics
	 * @param {zerk.game.engine.entity} entity Entity
	 */
	_syncEntityPhysics: function(entity) {
		
		var bodies=entity.components.physics.bodies;
		
		for (var key in bodies) {
			
			if (bodies[key]._physicsHandle && bodies[key].origin) {
				
				entity.components.position.x=
					bodies[key]._physicsHandle.GetPosition().x;
					
				entity.components.position.y=
					bodies[key]._physicsHandle.GetPosition().y;
				
				entity.components.position.angle=
					bodies[key]._physicsHandle.GetAngle();
				
			}
			
		}
		
		for (var key in bodies) {
			
			if (bodies[key]._physicsHandle) {
				
				bodies[key].x=
					bodies[key]._physicsHandle.GetPosition().x
					-entity.components.position.x;
					
				bodies[key].y=
					bodies[key]._physicsHandle.GetPosition().y
					-entity.components.position.y;
					
				bodies[key].angle=
					bodies[key]._physicsHandle.GetAngle();
				
			}
			
		}
		
	},
	
	/**
	 * Contact begin event handler
	 * 
	 * @method _onContactBegin
	 * @param {Object} contact Contact information
	 * @protected
	 */
	_onContactBegin: function(contact) {
		
		var sourceInfo=contact.GetFixtureA().GetUserData();
		var targetInfo=contact.GetFixtureB().GetUserData();
	
		/**
		 * Fires when two fixtures start colliding
		 * 
		 * @event contactbegin
		 * @param {zerk.game.engine.system.physics.box2d.fixture} sourceFixture Source fixture
		 * @param {zerk.game.engine.system.physics.box2d.fixture} targetFixture Target fixture
		 * @return {Boolean} Return false to Cancel bubble
		 */
		this.fireEvent(
			'contactbegin',
			sourceInfo,
			targetInfo
		);
		
	},
	
	/**
	 * Contact end event handler
	 * 
	 * @method _onContactEnd
	 * @param {Object} contact Contact information
	 * @protected
	 */
	_onContactEnd: function(contact) {
		
		var sourceInfo=contact.GetFixtureA().GetUserData();
		var targetInfo=contact.GetFixtureB().GetUserData();
		
		/**
		 * Fires when two fixtures stop colliding
		 * 
		 * @event contactend
		 * @param {zerk.game.engine.system.physics.box2d.fixture} sourceFixture Source 
		 * fixture
		 * @param {zerk.game.engine.system.physics.box2d.fixture} targetFixture Target 
		 * fixture
		 * @return {Boolean} Return false to Cancel bubble
		 */
		this.fireEvent(
			'contactend',
			sourceInfo,
			targetInfo
		);
		
	},
	
	/**
	 * Contact post solve event handler
	 * 
	 * @method _onContactPostSolve
	 * @param {Object} contact Contact information
	 * @param {Object} impulse Impulse information
	 * @protected
	 */
	_onContactPostSolve: function(contact,impulse) {
		
		var sourceFixture=contact.GetFixtureA().GetUserData();
		var targetFixture=contact.GetFixtureB().GetUserData();
		
		var sourceEntity=sourceFixture.body._entity;
		var targetEntity=targetFixture.body._entity;
	
		/**
		 * Fires before two fixtures start colliding
		 * 
		 * @event contactpostsolve
		 * @param {zerk.game.engine.system.physics.box2d.fixture} sourceFixture Source fixture
		 * @param {zerk.game.engine.system.physics.box2d.fixture} targetFixture Target fixture
		 * @param {Object} impulse
		 * @return {Boolean} Return false to Cancel bubble
		 */
		this.fireEvent(
			'contactpostsolve',
			sourceFixture,
			targetFixture,
			impulse
		);
		
	},
	
	/**
	 * Contact pre solve event handler
	 * 
	 * @method _onContactPreSolve
	 * @param {Object} contact Contact information
	 * @param {Object} oldManifold
	 * @protected
	 */
	_onContactPreSolve: function(contact,oldManifold) {
		
		/*
		 * TODO Implement ContactPreSolve event
		 */
		
	},
	
	/**
	 * Registers the contact listener event handlers
	 * 
	 * @method _addContactListener
	 * @protected
	 */
	_addContactListener: function() {
		
		var listener=new this._b2ContactListener();
		
		var self=this;
		
		listener.BeginContact=function(contact) {
			
			self._onContactBegin(contact);
			
		};
		
		listener.EndContact=function(contact) {
			
			self._onContactEnd(contact);
			
		};
		
		listener.PostSolve=function(contact,impulse) {
			
			self._onContactPostSolve(contact,impulse);
			
		};
		
		listener.PreSolve=function(contact,oldManifold) {
			
			self._onContactPreSolve(contact,oldManifold);
			
		};
		
		this._world.SetContactListener(listener);
		
	},
	

	/**
	 * Create the physics engine representation for an entity
	 * 
	 * @method createPhysics
	 * @param {zerk.game.engine.entity} entity Entity
	 */
	_createPhysics: function(entity) {
		
		for (var key in entity.components.physics.bodies) {
			
			this._createBody(entity,entity.components.physics.bodies[key]);
			
		}
		
		for (var key in entity.components.physics.joints) {
			
			this._createJoint(entity,entity.components.physics.joints[key]);
			
		}
		
	},
	
	/**
	 * Removes the physics engine representation for an entity
	 * 
	 * @method removePhysics
	 * @param {zerk.game.engine.entity} entity Entity
	 */
	_removePhysics: function(entity) {
		
		for (var key in entity.components.physics.bodies) {
			
			this._scheduleDestroyBody(
				entity.components.physics.bodies[key]._physicsHandle
			);
			
		}
		
		for (var key in entity.components.physics.joints) {
			
			this._scheduleDestroyJoint(
				entity.components.physics.joints[key]._physicsHandle
			);
			
		}
		
	},
	
	/**
	 * Creates a body
	 * 
	 * @method _createBody
	 * @param {zerk.game.engine.entity} entity Entity
	 * @param {zerk.game.engine.system.physics.box2d.body} body Body
	 * @return {Object} Body handle
	 * @protected
	 */
	_createBody: function(entity,body) {
		
		var bodyDef=new this._b2BodyDef;
		
		if (typeof body.moveable!='undefined' && body.moveable) {
			
			bodyDef.type=this._b2Body.b2_dynamicBody;
			
		} else if (typeof body.kinematic!='undefined' && body.kinematic) {
			
			bodyDef.type=this._b2Body.b2_kinematicBody;
			
		} else {
			
			bodyDef.type=this._b2Body.b2_staticBody;
			
		}
		
		var bodyState=entity.components.physics.bodies[body.key];
		var position=entity.components.position;
		
		
		
		// Setup position
		bodyDef.position.x=position.x+bodyState.x;
		bodyDef.position.y=position.y+bodyState.y;
		bodyDef.angle=bodyState.angle*Math.PI*2;
		bodyDef.fixedRotation=body.fixedRotation;
		
		bodyDef.userData={
			entity: entity,
			body: body.key
		};
		
		body._physicsHandle=this._world.CreateBody(bodyDef);
		
		// Create all fixtures of the body
		
		for (var key in body.fixtures) {
			
			body.fixtures[key]._physicsHandle=body._physicsHandle.CreateFixture(
				this._createFixture(
					entity,
					body,
					body.fixtures[key]
				)
			);
			
		}
		
		return body._physicsHandle;
	},
	
	/**
	 * Delegate method for fixture creation
	 * 
	 * @method _createFixture
	 * @param {zerk.game.engine.entity} entity Entity
	 * @param {zerk.game.engine.system.physics.box2d.body} body Body 
	 * @param {zerk.game.engine.system.physics.box2d.fixture} fixture Fixture
	 * @return {Object} Fixture handle
	 * @protected
	 */
	_createFixture: function(entity,body,fixture) {
		
		switch (fixture.shape) {
			case 'box':
				return this._createFixtureRectangle(
					entity,
					body,
					fixture
				);
				break;
			case 'circle':
				return this._createFixtureCircle(
					entity,
					body,
					fixture
				);
				break;
			case 'polygon':
				return this._createFixturePolygon(
					entity,
					body,
					fixture
				);
		}
		
	},
	
	/**
	 * Creates a rectangle shaped fixture
	 * 
	 * @method _createFixtureRectangle
	 * @param {zerk.game.engine.entity} entity Entity
	 * @param {zerk.game.engine.system.physics.box2d.body} body Body
	 * @param {zerk.game.engine.system.physics.box2d.fixture} fixture Fixture
	 * @return {Object} Fixture handle
	 * @protected
	 */
	_createFixtureRectangle: function(
		entity,
		body,
		fixture
	) {
		
		var fixDef=new this._b2FixtureDef;
		
		if (fixture.categoryBits!=null) {
			
			fixDef.filter.categoryBits=fixture.categoryBits;
			
		}
		if (fixture.maskBits!=null) {
			
			fixDef.filter.maskBits=fixture.maskBits;
			
		}
		
		fixDef.density=fixture.density;
		fixDef.friction=fixture.friction;
		fixDef.restitution=fixture.restitution;
		fixDef.isSensor=fixture.isSensor;
		fixDef.userData={
			entity: entity,
			body: body.key,
			fixture: fixture.key
		};
		
		fixDef.shape=new this._b2PolygonShape;
		
		var center=new this._b2Vec2(fixture.x, fixture.y);
		
		var width=((typeof fixture.width=='string') 
			? (body.width/100)*parseInt(fixture.width)
			: fixture.width);
		
		var height=((typeof fixture.height=='string') 
			? (body.height/100)*parseInt(fixture.height)
			: fixture.height);
		
		fixDef.shape.SetAsOrientedBox(
			width/2,
			height/2,
			center,
			fixture.angle
		);
		
		return fixDef;
		
	},
	
	/**
	 * Creates a circle shaped fixture
	 * 
	 * @method _createFixtureCircle
	 * @param {zerk.game.engine.entity} entity Entity
	 * @param {zerk.game.engine.system.physics.box2d.body} body Body
	 * @param {zerk.game.engine.system.physics.box2d.fixture} fixture Fixture
	 * @return {Object} Fixture handle
	 * @protected
	 */
	_createFixtureCircle: function(
		entity,
		body,
		fixture
	) {
		
		var fixDef=new this._b2FixtureDef;
		
		if (fixture.categoryBits!=null) {
			
			fixDef.filter.categoryBits=fixture.categoryBits;
			
		}
		if (fixture.maskBits!=null) {
			
			fixDef.filter.maskBits=fixture.maskBits;
			
		}
		
		fixDef.density=fixture.density;
		fixDef.friction=fixture.friction;
		fixDef.restitution=fixture.restitution;
		fixDef.isSensor=fixture.isSensor;
		fixDef.userData={
			entity: entity,
			body: body.key,
			fixture: fixture.key
		};
		
		fixDef.shape=new this._b2CircleShape(
			fixture.radius
		);
		
		fixDef.shape.SetLocalPosition(
			new this._b2Vec2(fixture.x, fixture.y)
		);
		
		return fixDef;
		
	},
	
	/**
	 * Creates a polygon shaped fixture
	 * 
	 * @method _createFixturePolygon
	 * @param {zerk.game.engine.entity} entity Entity
	 * @param {zerk.game.engine.system.physics.box2d.body} body Body
	 * @param {zerk.game.engine.system.physics.box2d.fixture} fixture Fixture
	 * @return {Object} Fixture handle
	 * @protected
	 */
	_createFixturePolygon: function(
		entity,
		body,
		fixture
	) {
		
		var fixDef=new this._b2FixtureDef;
		
		if (fixture.categoryBits!=null) {
			
			fixDef.filter.categoryBits=fixture.categoryBits;
			
		}
		if (fixture.maskBits!=null) {
			
			fixDef.filter.maskBits=fixture.maskBits;
			
		}
		
		fixDef.density=fixture.density;
		fixDef.friction=fixture.friction;
		fixDef.restitution=fixture.restitution;
		fixDef.isSensor=fixture.isSensor;
		fixDef.userData={
			entity: entity,
			body: body.key,
			fixture: fixture.key
		};
		
		fixDef.shape=new this._b2PolygonShape;
		
		// Check if the polygon is specified in clockwise order since Box2D requires that
		if (!zerk.helper.isPolygonClockwise(fixture.vertices)) {
			
			zerk.error({
				message: 'Polygon is not specified in clockwise order. Change'
					+' the order of the vertices in the fixture definition.',
				entityName: entity.name,
				bodyKey: body.key,
				fixtureKey: fixture.key,
				polygon: fixture.vertices,
				source: this
			});
			
		}
		
		// Create array of vertice instances
		
		var arr=[];
		
		for (var i=0;i<fixture.vertices.length;i++) {
			
			arr.push(
				new this._b2Vec2(
					fixture.vertices[i][0],
					fixture.vertices[i][1]
				)
			);
		}
		
		fixDef.shape.SetAsArray(arr, arr.length);
		
		return fixDef;
		
	},
	
	/**
	 * Delgate method for joint creation
	 * 
	 * @method _createJoint
	 * @param {zerk.game.engine.entity} entity Entity
	 * @param {zerk.game.engine.system.physics.box2d.joint} joint Joint
	 * @return {Object} Joint handle
	 * @protected
	 */
	_createJoint: function(entity,joint) {
		
		switch (joint.type) {
			case 'distance':
				return this._createJointDistance(entity,joint);
			case 'revolute':
				return this._createJointRevolute(entity,joint);
		}
		
	},
	
	/**
	 * Creates a distance joint
	 * 
	 * @method _createJointDistance
	 * @param {zerk.game.engine.entity} entity Entity
	 * @param {zerk.game.engine.system.physics.box2d.joint} joint Joint
	 * @return {Object} Joint handle
	 * @protected
	 */
	_createJointDistance: function(entity,joint) {
		
		var bodySource=entity.getBody(joint.source)._physicsHandle;
		var bodyTarget=entity.getBody(joint.target)._physicsHandle;
		
		var jointDef=new this._b2DistanceJointDef();
		
		jointDef.collideConnected=joint.collideConnected;
		jointDef.frequencyHz=joint.frequencyHz;
		jointDef.dampingRatio=joint.dampingRatio;
		
		// Create anchor vectors
		var anchorSource=bodySource.GetWorldCenter();
		var anchorTarget=bodyTarget.GetWorldCenter();
		
		jointDef.Initialize(
			bodySource,
			bodyTarget,
			anchorSource,
			anchorTarget
		);
		
		// Set local anchors
		jointDef.localAnchorA.Set(
			joint.anchorSourceX,
			joint.anchorSourceY
		);
		jointDef.localAnchorB.Set(
			joint.anchorTargetX,
			joint.anchorTargetY
		);
		
		return this._world.CreateJoint(jointDef);
		
	},
	
	/**
	 * Creates a revolute join
	 * 
	 * @method _createJointRevolute
	 * @param {zerk.game.engine.entity} entity Entity
	 * @param {zerk.game.engine.system.physics.box2d.joint} joint Joint
	 * @return {Object} Joint handle
	 * @protected
	 */
	_createJointRevolute: function(entity,joint) {
		
		var bodySource=this.getBody(entity,joint.source)._physicsHandle;
		var bodyTarget=this.getBody(entity,joint.target)._physicsHandle;
		
		var jointDef=new this._b2RevoluteJointDef();
		
		jointDef.enableLimit=joint.enableLimit;
		jointDef.lowerAngle=joint.lowerAngle;
		jointDef.upperAngle=joint.upperAngle;
		jointDef.enableMotor=joint.enableMotor;
		jointDef.motorSpeed=joint.motorSpeed;
		jointDef.maxMotorTorque=joint.maxMotorTorque;
		
		var anchorSource=bodySource.GetWorldCenter();
		anchorSource.x+=joint.anchorSourceX;
		anchorSource.y+=joint.anchorSourceY;
		
		jointDef.Initialize(
			bodySource,
			bodyTarget,
			anchorSource
		);
		
		return this._world.CreateJoint(jointDef);
		
	},
	
	/**
	 * Creates a mouse joint
	 * 
	 * @method _createJointMouse
	 * @param {Object} body Box2dWeb body
	 * @param {Float} targetX Horizontal position
	 * @param {Float} targetY Vertical position
	 * @return {Object} Joint handle
	 * @protected
	 */
	_createJointMouse: function(body,targetX,targetY) {
		
		var jointDef=new this._b2MouseJointDef();
		jointDef.bodyA=this._world.GetGroundBody();
		jointDef.bodyB=body;
		jointDef.target.Set(targetX,targetY);
		jointDef.collideConnected=true;
		jointDef.maxForce=300.0*body.GetMass();
		
		var joint=this._world.CreateJoint(jointDef);
		
		body.SetAwake(true);
		
		return joint;
		
	},
	
	/**
	 * Process mouse joint
	 * 
	 * @method _processMouseJoint
	 * @protected
	 */
	_processMouseJoint: function() {
		
		if (!this._config.enableMouseJoint) {
			
			return;
			
		}
		
		/*
		 * TODO Remove the mouse joint from the physics system
		 */
		var systemControl=this._getSystem('control');
		
		if (systemControl 
		&& systemControl.mouse.mouseLeftDown 
		&& !this._mouseJoint) {
			
			var body=this.getBodyAtMouse();
			
			if (body) {
				
				this._mouseJoint=this._createJointMouse(
					body,
					systemControl.mouse.mouseX,
					systemControl.mouse.mouseY
				);
				
			}
			
		}
		
		if (this._mouseJoint) {
			
			if (systemControl.mouse.mouseLeftDown) {
				
				this._mouseJoint.SetTarget(
					new this._b2Vec2(
						systemControl.mouse.mouseX,
						systemControl.mouse.mouseY
					)
				);
				
			} else {
				
				this._destroyJoint(this._mouseJoint);
				this._mouseJoint=null;
				
			}
			
		}
		
	},
	
	/**
	 * Callbak method for internal processing of getBodyAtMouse
	 * 
	 * @method _getBodyAtMouseCallback
	 * @param {Object} fixture Box2D fixture
	 * @return {Boolean}
	 * @protected
	 */
	_getBodyAtMouseCallback: function(fixture) {
		
		/*
		 * TODO Remove global call zerk.game._engine._system.physics
		 */
		var me=zerk.game._engine._system.physics;
		
		if (fixture.GetBody().GetType()
		!=me._b2Body.b2_staticBody) {
			
			if (fixture.GetShape().TestPoint(
				fixture.GetBody().GetTransform(),
				self._mouseJointVec
			)) {
				
				self._selectedBody=fixture.GetBody();
				return false;
				
			}
			
		}
		return true;
		
	}
	
});