470 lines
12 KiB
JavaScript
470 lines
12 KiB
JavaScript
|
/*
|
|||
|
* 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.
|
|||
|
var b2Body = Class.create();
|
|||
|
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 -------------------
|
|||
|
|
|||
|
initialize: 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;
|
|||
|
},
|
|||
|
// 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;
|