API Docs for: 1.0.0
Show:

File: src\fork\box2d\dynamics\b2Body.js

/*
* Copyright (c) 2006-2007 Erin Catto http:
*
* This software is provided 'as-is', without any express or implied
* warranty.  In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked, and must not be
* misrepresented the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/

/**
 * A rigid body. Internal computation are done in terms
 * of the center of mass position. The center of mass may
 * be offset from the body's origin.
 *
 * @class b2Body
 * @constructor
 * @param bd
 * @param world
 */
var b2Body = function (bd, world) {
	// initialize instance variables for references
	this.sMat0 = new b2Mat22();
	this.m_position = new b2Vec2();
	this.m_R = new b2Mat22(0);
	this.m_position0 = new b2Vec2();
	//

	var i = 0;
	var sd;
	var massData;

	this.m_flags = 0;
	this.m_position.SetV( bd.position );
	this.m_rotation = bd.rotation;
	this.m_R.Set(this.m_rotation);
	this.m_position0.SetV(this.m_position);
	this.m_rotation0 = this.m_rotation;
	this.m_world = world;

	this.m_linearDamping = b2Math.b2Clamp(1.0 - bd.linearDamping, 0.0, 1.0);
	this.m_angularDamping = b2Math.b2Clamp(1.0 - bd.angularDamping, 0.0, 1.0);

	this.m_force = new b2Vec2(0.0, 0.0);
	this.m_torque = 0.0;

	this.m_mass = 0.0;

	var massDatas = new Array(b2Settings.b2_maxShapesPerBody);
	for (i = 0; i < b2Settings.b2_maxShapesPerBody; i++){
		massDatas[i] = new b2MassData();
	}

	// Compute the shape mass properties, the bodies total mass and COM.
	this.m_shapeCount = 0;
	this.m_center = new b2Vec2(0.0, 0.0);
	for (i = 0; i < b2Settings.b2_maxShapesPerBody; ++i)
	{
		sd = bd.shapes[i];
		if (sd == null) break;
		massData = massDatas[ i ];
		sd.ComputeMass(massData);
		this.m_mass += massData.mass;
		//this.m_center += massData->mass * (sd->localPosition + massData->center);
		this.m_center.x += massData.mass * (sd.localPosition.x + massData.center.x);
		this.m_center.y += massData.mass * (sd.localPosition.y + massData.center.y);
		++this.m_shapeCount;
	}

	// Compute center of mass, and shift the origin to the COM.
	if (this.m_mass > 0.0)
	{
		this.m_center.Multiply( 1.0 / this.m_mass );
		this.m_position.Add( b2Math.b2MulMV(this.m_R, this.m_center) );
	}
	else
	{
		this.m_flags |= b2Body.e_staticFlag;
	}

	// Compute the moment of inertia.
	this.m_I = 0.0;
	for (i = 0; i < this.m_shapeCount; ++i)
	{
		sd = bd.shapes[i];
		massData = massDatas[ i ];
		this.m_I += massData.I;
		var r = b2Math.SubtractVV( b2Math.AddVV(sd.localPosition, massData.center), this.m_center );
		this.m_I += massData.mass * b2Math.b2Dot(r, r);
	}

	if (this.m_mass > 0.0)
	{
		this.m_invMass = 1.0 / this.m_mass;
	}
	else
	{
		this.m_invMass = 0.0;
	}

	if (this.m_I > 0.0 && bd.preventRotation == false)
	{
		this.m_invI = 1.0 / this.m_I;
	}
	else
	{
		this.m_I = 0.0;
		this.m_invI = 0.0;
	}

	// Compute the center of mass velocity.
	this.m_linearVelocity = b2Math.AddVV(bd.linearVelocity, b2Math.b2CrossFV(bd.angularVelocity, this.m_center));
	this.m_angularVelocity = bd.angularVelocity;

	this.m_jointList = null;
	this.m_contactList = null;
	this.m_prev = null;
	this.m_next = null;

	// Create the shapes.
	this.m_shapeList = null;
	for (i = 0; i < this.m_shapeCount; ++i)
	{
		sd = bd.shapes[i];
		var shape = b2Shape.Create(sd, this, this.m_center);
		shape.m_next = this.m_shapeList;
		this.m_shapeList = shape;
	}

	this.m_sleepTime = 0.0;
	if (bd.allowSleep)
	{
		this.m_flags |= b2Body.e_allowSleepFlag;
	}
	if (bd.isSleeping)
	{
		this.m_flags |= b2Body.e_sleepFlag;
	}

	if ((this.m_flags & b2Body.e_sleepFlag)  || this.m_invMass == 0.0)
	{
		this.m_linearVelocity.Set(0.0, 0.0);
		this.m_angularVelocity = 0.0;
	}

	this.m_userData = bd.userData;
};

b2Body.prototype = 
{
	// Set the position of the body's origin and rotation (radians).
	// This breaks any contacts and wakes the other bodies.
	SetOriginPosition: function(position, rotation){
		if (this.IsFrozen())
		{
			return;
		}

		this.m_rotation = rotation;
		this.m_R.Set(this.m_rotation);
		this.m_position = b2Math.AddVV(position , b2Math.b2MulMV(this.m_R, this.m_center));

		this.m_position0.SetV(this.m_position);
		this.m_rotation0 = this.m_rotation;

		for (var s = this.m_shapeList; s != null; s = s.m_next)
		{
			s.Synchronize(this.m_position, this.m_R, this.m_position, this.m_R);
		}

		this.m_world.m_broadPhase.Commit();
	},

	// Get the position of the body's origin. The body's origin does not
	// necessarily coincide with the center of mass. It depends on how the
	// shapes are created.
	GetOriginPosition: function(){
		return b2Math.SubtractVV(this.m_position, b2Math.b2MulMV(this.m_R, this.m_center));
	},

	// Set the position of the body's center of mass and rotation (radians).
	// This breaks any contacts and wakes the other bodies.
	SetCenterPosition: function(position, rotation){
		if (this.IsFrozen())
		{
			return;
		}

		this.m_rotation = rotation;
		this.m_R.Set(this.m_rotation);
		this.m_position.SetV( position );

		this.m_position0.SetV(this.m_position);
		this.m_rotation0 = this.m_rotation;

		for (var s = this.m_shapeList; s != null; s = s.m_next)
		{
			s.Synchronize(this.m_position, this.m_R, this.m_position, this.m_R);
		}

		this.m_world.m_broadPhase.Commit();
	},

	// Get the position of the body's center of mass. The body's center of mass
	// does not necessarily coincide with the body's origin. It depends on how the
	// shapes are created.
	GetCenterPosition: function(){
		return this.m_position;
	},

	// Get the rotation in radians.
	GetRotation: function(){
		return this.m_rotation;
	},

	GetRotationMatrix: function(){
		return this.m_R;
	},

	// Set/Get the linear velocity of the center of mass.
	SetLinearVelocity: function(v){
		this.m_linearVelocity.SetV(v);
	},
	GetLinearVelocity: function(){
		return this.m_linearVelocity;
	},

	// Set/Get the angular velocity.
	SetAngularVelocity: function(w){
		this.m_angularVelocity = w;
	},
	GetAngularVelocity: function(){
		return this.m_angularVelocity;
	},

	// Apply a force at a world point. Additive.
	ApplyForce: function(force, point)
	{
		if (this.IsSleeping() == false)
		{
			this.m_force.Add( force );
			this.m_torque += b2Math.b2CrossVV(b2Math.SubtractVV(point, this.m_position), force);
		}
	},

	// Apply a torque. Additive.
	ApplyTorque: function(torque)
	{
		if (this.IsSleeping() == false)
		{
			this.m_torque += torque;
		}
	},

	// Apply an impulse at a point. This immediately modifies the velocity.
	ApplyImpulse: function(impulse, point)
	{
		if (this.IsSleeping() == false)
		{
			this.m_linearVelocity.Add( b2Math.MulFV(this.m_invMass, impulse) );
			this.m_angularVelocity += ( this.m_invI * b2Math.b2CrossVV( b2Math.SubtractVV(point, this.m_position), impulse)  );
		}
	},

	GetMass: function(){
		return this.m_mass;
	},

	GetInertia: function(){
		return this.m_I;
	},

	// Get the world coordinates of a point give the local coordinates
	// relative to the body's center of mass.
	GetWorldPoint: function(localPoint){
		return b2Math.AddVV(this.m_position , b2Math.b2MulMV(this.m_R, localPoint));
	},

	// Get the world coordinates of a vector given the local coordinates.
	GetWorldVector: function(localVector){
		return b2Math.b2MulMV(this.m_R, localVector);
	},

	// Returns a local point relative to the center of mass given a world point.
	GetLocalPoint: function(worldPoint){
		return b2Math.b2MulTMV(this.m_R, b2Math.SubtractVV(worldPoint, this.m_position));
	},

	// Returns a local vector given a world vector.
	GetLocalVector: function(worldVector){
		return b2Math.b2MulTMV(this.m_R, worldVector);
	},

	// Is this body static (immovable)?
	IsStatic: function(){
		return (this.m_flags & b2Body.e_staticFlag) == b2Body.e_staticFlag;
	},

	IsFrozen: function()
	{
		return (this.m_flags & b2Body.e_frozenFlag) == b2Body.e_frozenFlag;
	},

	// Is this body sleeping (not simulating).
	IsSleeping: function(){
		return (this.m_flags & b2Body.e_sleepFlag) == b2Body.e_sleepFlag;
	},

	// You can disable sleeping on this particular body.
	AllowSleeping: function(flag)
	{
		if (flag)
		{
			this.m_flags |= b2Body.e_allowSleepFlag;
		}
		else
		{
			this.m_flags &= ~b2Body.e_allowSleepFlag;
			this.WakeUp();
		}
	},

	// Wake up this body so it will begin simulating.
	WakeUp: function(){
		this.m_flags &= ~b2Body.e_sleepFlag;
		this.m_sleepTime = 0.0;
	},

	// Get the list of all shapes attached to this body.
	GetShapeList: function(){
		return this.m_shapeList;
	},

	GetContactList: function()
	{
		return this.m_contactList;
	},

	GetJointList: function()
	{
		return this.m_jointList;
	},

	// Get the next body in the world's body list.
	GetNext: function(){
		return this.m_next;
	},

	GetUserData: function(){
		return this.m_userData;
	},

	//--------------- Internals Below -------------------

	// does not support destructors
	/*~b2Body(){
		b2Shape* s = this.m_shapeList;
		while (s)
		{
			b2Shape* s0 = s;
			s = s->this.m_next;

			b2Shape::this.Destroy(s0);
		}
	}*/

	Destroy: function(){
		var s = this.m_shapeList;
		while (s)
		{
			var s0 = s;
			s = s.m_next;

			b2Shape.Destroy(s0);
		}
	},

	// Temp mat
	sMat0: new b2Mat22(),
	SynchronizeShapes: function(){
		//b2Mat22 R0(this.m_rotation0);
		this.sMat0.Set(this.m_rotation0);
		for (var s = this.m_shapeList; s != null; s = s.m_next)
		{
			s.Synchronize(this.m_position0, this.sMat0, this.m_position, this.m_R);
		}
	},

	QuickSyncShapes: function(){
		for (var s = this.m_shapeList; s != null; s = s.m_next)
		{
			s.QuickSync(this.m_position, this.m_R);
		}
	},

	// This is used to prevent connected bodies from colliding.
	// It may lie, depending on the collideConnected flag.
	IsConnected: function(other){
		for (var jn = this.m_jointList; jn != null; jn = jn.next)
		{
			if (jn.other == other)
				return jn.joint.m_collideConnected == false;
		}

		return false;
	},

	Freeze: function(){
		this.m_flags |= b2Body.e_frozenFlag;
		this.m_linearVelocity.SetZero();
		this.m_angularVelocity = 0.0;

		for (var s = this.m_shapeList; s != null; s = s.m_next)
		{
			s.DestroyProxy();
		}
	},

	m_flags: 0,

	m_position: new b2Vec2(),
	m_rotation: null,
	m_R: new b2Mat22(0),

	// Conservative advancement data.
	m_position0: new b2Vec2(),
	m_rotation0: null,

	m_linearVelocity: null,
	m_angularVelocity: null,

	m_force: null,
	m_torque: null,

	m_center: null,

	m_world: null,
	m_prev: null,
	m_next: null,

	m_shapeList: null,
	m_shapeCount: 0,

	m_jointList: null,
	m_contactList: null,

	m_mass: null,
	m_invMass: null,
	m_I: null,
	m_invI: null,

	m_linearDamping: null,
	m_angularDamping: null,

	m_sleepTime: null,

	m_userData: null
};

b2Body.e_staticFlag = 0x0001;
b2Body.e_frozenFlag = 0x0002;
b2Body.e_islandFlag = 0x0004;
b2Body.e_sleepFlag = 0x0008;
b2Body.e_allowSleepFlag = 0x0010;
b2Body.e_destroyFlag = 0x0020;