@box2d/debug-draw
Version:
Debug drawing helper for @box2d
951 lines (950 loc) • 34.1 kB
JavaScript
"use strict";
// MIT License
Object.defineProperty(exports, "__esModule", { value: true });
exports.b2Body = exports.b2BodyType = void 0;
// Copyright (c) 2019 Erin Catto
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
// DEBUG: import { b2Assert } from "../common/b2_common";
const b2_math_1 = require("../common/b2_math");
const b2_shape_1 = require("../collision/b2_shape");
const b2_fixture_1 = require("./b2_fixture");
const b2_common_1 = require("../common/b2_common");
/**
* The body type.
* static: zero mass, zero velocity, may be manually moved
* kinematic: zero mass, non-zero velocity set by user, moved by solver
* dynamic: positive mass, non-zero velocity determined by forces, moved by solver
*/
var b2BodyType;
(function (b2BodyType) {
b2BodyType[b2BodyType["b2_staticBody"] = 0] = "b2_staticBody";
b2BodyType[b2BodyType["b2_kinematicBody"] = 1] = "b2_kinematicBody";
b2BodyType[b2BodyType["b2_dynamicBody"] = 2] = "b2_dynamicBody";
})(b2BodyType || (exports.b2BodyType = b2BodyType = {}));
/**
* A rigid body. These are created via b2World::CreateBody.
*/
class b2Body {
/** @internal */
constructor(bd, world) {
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p;
/** @internal */
this.m_type = b2BodyType.b2_staticBody;
/** @internal */
this.m_islandFlag = false;
/** @internal */
this.m_awakeFlag = false;
/** @internal */
this.m_autoSleepFlag = false;
/** @internal */
this.m_bulletFlag = false;
/** @internal */
this.m_fixedRotationFlag = false;
/** @internal */
this.m_enabledFlag = false;
/** @internal */
this.m_toiFlag = false;
/** @internal */
this.m_islandIndex = 0;
/** @internal */
this.m_xf = new b2_math_1.b2Transform(); // the body origin transform
/** @internal */
this.m_sweep = new b2_math_1.b2Sweep(); // the swept motion for CCD
/** @internal */
this.m_linearVelocity = new b2_math_1.b2Vec2();
/** @internal */
this.m_angularVelocity = 0;
/** @internal */
this.m_force = new b2_math_1.b2Vec2();
/** @internal */
this.m_torque = 0;
/** @internal */
this.m_prev = null;
/** @internal */
this.m_next = null;
/** @internal */
this.m_fixtureList = null;
/** @internal */
this.m_fixtureCount = 0;
/** @internal */
this.m_jointList = null;
/** @internal */
this.m_contactList = null;
/** @internal */
this.m_mass = 1;
/** @internal */
this.m_invMass = 1;
/**
* Rotational inertia about the center of mass.
* @internal
*/
this.m_I = 0;
/** @internal */
this.m_invI = 0;
/** @internal */
this.m_linearDamping = 0;
/** @internal */
this.m_angularDamping = 0;
/** @internal */
this.m_gravityScale = 1;
/** @internal */
this.m_sleepTime = 0;
/** @internal */
this.m_userData = {};
this.m_bulletFlag = (_a = bd.bullet) !== null && _a !== void 0 ? _a : false;
this.m_fixedRotationFlag = (_b = bd.fixedRotation) !== null && _b !== void 0 ? _b : false;
this.m_autoSleepFlag = (_c = bd.allowSleep) !== null && _c !== void 0 ? _c : true;
if (((_d = bd.awake) !== null && _d !== void 0 ? _d : true) && ((_e = bd.type) !== null && _e !== void 0 ? _e : b2BodyType.b2_staticBody) !== b2BodyType.b2_staticBody) {
this.m_awakeFlag = true;
}
this.m_enabledFlag = (_f = bd.enabled) !== null && _f !== void 0 ? _f : true;
this.m_world = world;
this.m_xf.p.Copy((_g = bd.position) !== null && _g !== void 0 ? _g : b2_math_1.b2Vec2.ZERO);
this.m_xf.q.Set((_h = bd.angle) !== null && _h !== void 0 ? _h : 0);
this.m_sweep.localCenter.SetZero();
this.m_sweep.c0.Copy(this.m_xf.p);
this.m_sweep.c.Copy(this.m_xf.p);
this.m_sweep.a0 = this.m_sweep.a = this.m_xf.q.GetAngle();
this.m_sweep.alpha0 = 0;
this.m_linearVelocity.Copy((_j = bd.linearVelocity) !== null && _j !== void 0 ? _j : b2_math_1.b2Vec2.ZERO);
this.m_angularVelocity = (_k = bd.angularVelocity) !== null && _k !== void 0 ? _k : 0;
this.m_linearDamping = (_l = bd.linearDamping) !== null && _l !== void 0 ? _l : 0;
this.m_angularDamping = (_m = bd.angularDamping) !== null && _m !== void 0 ? _m : 0;
this.m_gravityScale = (_o = bd.gravityScale) !== null && _o !== void 0 ? _o : 1;
this.m_force.SetZero();
this.m_torque = 0;
this.m_sleepTime = 0;
this.m_type = (_p = bd.type) !== null && _p !== void 0 ? _p : b2BodyType.b2_staticBody;
this.m_mass = 0;
this.m_invMass = 0;
this.m_I = 0;
this.m_invI = 0;
if (bd.userData)
this.SetUserData(bd.userData);
this.m_fixtureList = null;
this.m_fixtureCount = 0;
}
/**
* Creates a fixture and attach it to this body. Use this function if you need
* to set some fixture parameters, like friction. Otherwise you can create the
* fixture directly from a shape.
* If the density is non-zero, this function automatically updates the mass of the body.
* Contacts are not created until the next time step.
*
* @param def The fixture definition.
* @warning This function is locked during callbacks.
*/
CreateFixture(def) {
(0, b2_common_1.b2Assert)(!this.m_world.IsLocked());
const fixture = new b2_fixture_1.b2Fixture(this, def);
if (this.m_enabledFlag) {
const broadPhase = this.m_world.m_contactManager.m_broadPhase;
fixture.CreateProxies(broadPhase, this.m_xf);
}
fixture.m_next = this.m_fixtureList;
this.m_fixtureList = fixture;
++this.m_fixtureCount;
// Adjust mass properties if needed.
if (fixture.m_density > 0) {
this.ResetMassData();
}
// Let the world know we have a new fixture. This will cause new contacts
// to be created at the beginning of the next time step.
this.m_world.m_newContacts = true;
return fixture;
}
/**
* Destroy a fixture. This removes the fixture from the broad-phase and
* destroys all contacts associated with this fixture. This will
* automatically adjust the mass of the body if the body is dynamic and the
* fixture has positive density.
* All fixtures attached to a body are implicitly destroyed when the body is destroyed.
*
* @param fixture The fixture to be removed.
* @warning This function is locked during callbacks.
*/
DestroyFixture(fixture) {
(0, b2_common_1.b2Assert)(!this.m_world.IsLocked());
// DEBUG: b2Assert(fixture.m_body === this);
// Remove the fixture from this body's singly linked list.
// DEBUG: b2Assert(this.m_fixtureCount > 0);
let node = this.m_fixtureList;
let ppF = null;
// DEBUG: let found = false;
while (node !== null) {
if (node === fixture) {
if (ppF) {
ppF.m_next = fixture.m_next;
}
else {
this.m_fixtureList = fixture.m_next;
}
// DEBUG: found = true;
break;
}
ppF = node;
node = node.m_next;
}
// You tried to remove a shape that is not attached to this body.
// DEBUG: b2Assert(found);
const density = fixture.m_density;
// Destroy any contacts associated with the fixture.
let edge = this.m_contactList;
while (edge) {
const c = edge.contact;
edge = edge.next;
const fixtureA = c.GetFixtureA();
const fixtureB = c.GetFixtureB();
if (fixture === fixtureA || fixture === fixtureB) {
// This destroys the contact and removes it from
// this body's contact list.
this.m_world.m_contactManager.Destroy(c);
}
}
if (this.m_enabledFlag) {
const broadPhase = this.m_world.m_contactManager.m_broadPhase;
fixture.DestroyProxies(broadPhase);
}
// fixture.m_body = null;
fixture.m_next = null;
--this.m_fixtureCount;
// Reset the mass data.
// Reset the mass data
if (density > 0.0) {
this.ResetMassData();
}
}
/**
* Set the position of the body's origin and rotation.
* This breaks any contacts and wakes the other bodies.
* Manipulating a body's transform may cause non-physical behavior.
*
* @param position The world position of the body's local origin.
* @param angle The world rotation in radians.
*/
SetTransformVec(position, angle) {
this.SetTransformXY(position.x, position.y, angle);
}
SetTransformXY(x, y, angle) {
(0, b2_common_1.b2Assert)(!this.m_world.IsLocked());
this.m_xf.q.Set(angle);
this.m_xf.p.Set(x, y);
b2_math_1.b2Transform.MultiplyVec2(this.m_xf, this.m_sweep.localCenter, this.m_sweep.c);
this.m_sweep.a = angle;
this.m_sweep.c0.Copy(this.m_sweep.c);
this.m_sweep.a0 = angle;
const broadPhase = this.m_world.m_contactManager.m_broadPhase;
for (let f = this.m_fixtureList; f; f = f.m_next) {
f.Synchronize(broadPhase, this.m_xf, this.m_xf);
}
// Check for new contacts the next step
this.m_world.m_newContacts = true;
}
SetTransform(xf) {
this.SetTransformVec(xf.p, xf.GetAngle());
}
/**
* Get the body transform for the body's origin.
*
* @returns The world transform of the body's origin.
*/
GetTransform() {
return this.m_xf;
}
/**
* Get the world body origin position.
*
* @returns The world position of the body's origin.
*/
GetPosition() {
return this.m_xf.p;
}
/**
* Get the angle in radians.
*
* @returns The current world rotation angle in radians.
*/
GetAngle() {
return this.m_sweep.a;
}
SetAngle(angle) {
this.SetTransformVec(this.GetPosition(), angle);
}
/**
* Get the world position of the center of mass.
*/
GetWorldCenter() {
return this.m_sweep.c;
}
/**
* Get the local position of the center of mass.
*/
GetLocalCenter() {
return this.m_sweep.localCenter;
}
/**
* Set the linear velocity of the center of mass.
*
* @param v The new linear velocity of the center of mass.
*/
SetLinearVelocity(v) {
if (this.m_type === b2BodyType.b2_staticBody) {
return;
}
if (b2_math_1.b2Vec2.Dot(v, v) > 0) {
this.SetAwake(true);
}
this.m_linearVelocity.Copy(v);
}
/**
* Get the linear velocity of the center of mass.
*
* @returns The linear velocity of the center of mass.
*/
GetLinearVelocity() {
return this.m_linearVelocity;
}
/**
* Set the angular velocity.
*
* @param omega The new angular velocity in radians/second.
*/
SetAngularVelocity(w) {
if (this.m_type === b2BodyType.b2_staticBody) {
return;
}
if (w * w > 0) {
this.SetAwake(true);
}
this.m_angularVelocity = w;
}
/**
* Get the angular velocity.
*
* @returns The angular velocity in radians/second.
*/
GetAngularVelocity() {
return this.m_angularVelocity;
}
/**
* Apply a force at a world point. If the force is not
* applied at the center of mass, it will generate a torque and
* affect the angular velocity. This wakes up the body.
*
* @param force The world force vector, usually in Newtons (N).
* @param point The world position of the point of application.
* @param wake Also wake up the body
*/
ApplyForce(force, point, wake = true) {
if (this.m_type !== b2BodyType.b2_dynamicBody) {
return;
}
if (wake && !this.m_awakeFlag) {
this.SetAwake(true);
}
// Don't accumulate a force if the body is sleeping
if (this.m_awakeFlag) {
this.m_force.x += force.x;
this.m_force.y += force.y;
this.m_torque += (point.x - this.m_sweep.c.x) * force.y - (point.y - this.m_sweep.c.y) * force.x;
}
}
/**
* Apply a force to the center of mass. This wakes up the body.
*
* @param force The world force vector, usually in Newtons (N).
* @param wake Also wake up the body
*/
ApplyForceToCenter(force, wake = true) {
if (this.m_type !== b2BodyType.b2_dynamicBody) {
return;
}
if (wake && !this.m_awakeFlag) {
this.SetAwake(true);
}
// Don't accumulate a force if the body is sleeping
if (this.m_awakeFlag) {
this.m_force.x += force.x;
this.m_force.y += force.y;
}
}
/**
* Apply a torque. This affects the angular velocity
* without affecting the linear velocity of the center of mass.
*
* @param torque About the z-axis (out of the screen), usually in N-m.
* @param wake Also wake up the body
*/
ApplyTorque(torque, wake = true) {
if (this.m_type !== b2BodyType.b2_dynamicBody) {
return;
}
if (wake && !this.m_awakeFlag) {
this.SetAwake(true);
}
// Don't accumulate a force if the body is sleeping
if (this.m_awakeFlag) {
this.m_torque += torque;
}
}
/**
* Apply an impulse at a point. This immediately modifies the velocity.
* It also modifies the angular velocity if the point of application
* is not at the center of mass. This wakes up the body.
*
* @param impulse The world impulse vector, usually in N-seconds or kg-m/s.
* @param point The world position of the point of application.
* @param wake Also wake up the body
*/
ApplyLinearImpulse(impulse, point, wake = true) {
if (this.m_type !== b2BodyType.b2_dynamicBody) {
return;
}
if (wake && !this.m_awakeFlag) {
this.SetAwake(true);
}
// Don't accumulate velocity if the body is sleeping
if (this.m_awakeFlag) {
this.m_linearVelocity.x += this.m_invMass * impulse.x;
this.m_linearVelocity.y += this.m_invMass * impulse.y;
this.m_angularVelocity +=
this.m_invI * ((point.x - this.m_sweep.c.x) * impulse.y - (point.y - this.m_sweep.c.y) * impulse.x);
}
}
/**
* Apply an impulse to the center of mass. This immediately modifies the velocity.
*
* @param impulse The world impulse vector, usually in N-seconds or kg-m/s.
* @param wake Also wake up the body
*/
ApplyLinearImpulseToCenter(impulse, wake = true) {
if (this.m_type !== b2BodyType.b2_dynamicBody) {
return;
}
if (wake && !this.m_awakeFlag) {
this.SetAwake(true);
}
// Don't accumulate velocity if the body is sleeping
if (this.m_awakeFlag) {
this.m_linearVelocity.x += this.m_invMass * impulse.x;
this.m_linearVelocity.y += this.m_invMass * impulse.y;
}
}
/**
* Apply an angular impulse.
*
* @param impulse The angular impulse in units of kg*m*m/s
* @param wake Also wake up the body
*/
ApplyAngularImpulse(impulse, wake = true) {
if (this.m_type !== b2BodyType.b2_dynamicBody) {
return;
}
if (wake && !this.m_awakeFlag) {
this.SetAwake(true);
}
// Don't accumulate velocity if the body is sleeping
if (this.m_awakeFlag) {
this.m_angularVelocity += this.m_invI * impulse;
}
}
/**
* Get the total mass of the body.
*
* @returns The mass, usually in kilograms (kg).
*/
GetMass() {
return this.m_mass;
}
/**
* Get the rotational inertia of the body about the local origin.
*
* @returns The rotational inertia, usually in kg-m^2.
*/
GetInertia() {
return this.m_I + this.m_mass * b2_math_1.b2Vec2.Dot(this.m_sweep.localCenter, this.m_sweep.localCenter);
}
/**
* Get the mass data of the body.
*
* @returns A struct containing the mass, inertia and center of the body.
*/
GetMassData(data) {
data.mass = this.m_mass;
data.I = this.m_I + this.m_mass * b2_math_1.b2Vec2.Dot(this.m_sweep.localCenter, this.m_sweep.localCenter);
data.center.Copy(this.m_sweep.localCenter);
return data;
}
/**
* Set the mass properties to override the mass properties of the fixtures.
* Note that this changes the center of mass position.
* Note that creating or destroying fixtures can also alter the mass.
* This function has no effect if the body isn't dynamic.
*
* @param massData The mass properties.
*/
SetMassData(massData) {
(0, b2_common_1.b2Assert)(!this.m_world.IsLocked());
if (this.m_type !== b2BodyType.b2_dynamicBody) {
return;
}
this.m_invMass = 0;
this.m_I = 0;
this.m_invI = 0;
this.m_mass = massData.mass;
if (this.m_mass <= 0) {
this.m_mass = 1;
}
this.m_invMass = 1 / this.m_mass;
if (massData.I > 0 && !this.m_fixedRotationFlag) {
this.m_I = massData.I - this.m_mass * b2_math_1.b2Vec2.Dot(massData.center, massData.center);
// DEBUG: b2Assert(this.m_I > 0);
this.m_invI = 1 / this.m_I;
}
// Move center of mass.
const oldCenter = b2Body.SetMassData_s_oldCenter.Copy(this.m_sweep.c);
this.m_sweep.localCenter.Copy(massData.center);
b2_math_1.b2Transform.MultiplyVec2(this.m_xf, this.m_sweep.localCenter, this.m_sweep.c);
this.m_sweep.c0.Copy(this.m_sweep.c);
// Update center of mass velocity.
b2_math_1.b2Vec2.AddCrossScalarVec2(this.m_linearVelocity, this.m_angularVelocity, b2_math_1.b2Vec2.Subtract(this.m_sweep.c, oldCenter, b2_math_1.b2Vec2.s_t0), this.m_linearVelocity);
}
/**
* This resets the mass properties to the sum of the mass properties of the fixtures.
* This normally does not need to be called unless you called SetMassData to override
* the mass and you later want to reset the mass.
*/
ResetMassData() {
// Compute mass data from shapes. Each shape has its own density.
this.m_mass = 0;
this.m_invMass = 0;
this.m_I = 0;
this.m_invI = 0;
this.m_sweep.localCenter.SetZero();
// Static and kinematic bodies have zero mass.
if (this.m_type === b2BodyType.b2_staticBody || this.m_type === b2BodyType.b2_kinematicBody) {
this.m_sweep.c0.Copy(this.m_xf.p);
this.m_sweep.c.Copy(this.m_xf.p);
this.m_sweep.a0 = this.m_sweep.a;
return;
}
// DEBUG: b2Assert(this.m_type === b2BodyType.b2_dynamicBody);
// Accumulate mass over all fixtures.
const localCenter = b2Body.ResetMassData_s_localCenter.SetZero();
for (let f = this.m_fixtureList; f; f = f.m_next) {
if (f.m_density === 0) {
continue;
}
const massData = f.GetMassData(b2Body.ResetMassData_s_massData);
this.m_mass += massData.mass;
localCenter.AddScaled(massData.mass, massData.center);
this.m_I += massData.I;
}
// Compute center of mass.
if (this.m_mass > 0) {
this.m_invMass = 1 / this.m_mass;
localCenter.Scale(this.m_invMass);
}
if (this.m_I > 0 && !this.m_fixedRotationFlag) {
// Center the inertia about the center of mass.
this.m_I -= this.m_mass * b2_math_1.b2Vec2.Dot(localCenter, localCenter);
// DEBUG: b2Assert(this.m_I > 0);
this.m_invI = 1 / this.m_I;
}
else {
this.m_I = 0;
this.m_invI = 0;
}
// Move center of mass.
const oldCenter = b2Body.ResetMassData_s_oldCenter.Copy(this.m_sweep.c);
this.m_sweep.localCenter.Copy(localCenter);
b2_math_1.b2Transform.MultiplyVec2(this.m_xf, this.m_sweep.localCenter, this.m_sweep.c);
this.m_sweep.c0.Copy(this.m_sweep.c);
// Update center of mass velocity.
b2_math_1.b2Vec2.AddCrossScalarVec2(this.m_linearVelocity, this.m_angularVelocity, b2_math_1.b2Vec2.Subtract(this.m_sweep.c, oldCenter, b2_math_1.b2Vec2.s_t0), this.m_linearVelocity);
}
/**
* Get the world coordinates of a point given the local coordinates.
*
* @param localPoint A point on the body measured relative the the body's origin.
* @returns The same point expressed in world coordinates.
*/
GetWorldPoint(localPoint, out) {
return b2_math_1.b2Transform.MultiplyVec2(this.m_xf, localPoint, out);
}
/**
* Get the world coordinates of a vector given the local coordinates.
*
* @param localVector A vector fixed in the body.
* @returns The same vector expressed in world coordinates.
*/
GetWorldVector(localVector, out) {
return b2_math_1.b2Rot.MultiplyVec2(this.m_xf.q, localVector, out);
}
/**
* Gets a local point relative to the body's origin given a world point.
*
* @param a Point in world coordinates.
* @returns The corresponding local point relative to the body's origin.
*/
GetLocalPoint(worldPoint, out) {
return b2_math_1.b2Transform.TransposeMultiplyVec2(this.m_xf, worldPoint, out);
}
/**
* Gets a local vector given a world vector.
*
* @param a Vector in world coordinates.
* @returns The corresponding local vector.
*/
GetLocalVector(worldVector, out) {
return b2_math_1.b2Rot.TransposeMultiplyVec2(this.m_xf.q, worldVector, out);
}
/**
* Get the world linear velocity of a world point attached to this body.
*
* @param a Point in world coordinates.
* @returns The world velocity of a point.
*/
GetLinearVelocityFromWorldPoint(worldPoint, out) {
return b2_math_1.b2Vec2.AddCrossScalarVec2(this.m_linearVelocity, this.m_angularVelocity, b2_math_1.b2Vec2.Subtract(worldPoint, this.m_sweep.c, b2_math_1.b2Vec2.s_t0), out);
}
/**
* Get the world velocity of a local point.
*
* @param a Point in local coordinates.
* @returns The world velocity of a point.
*/
GetLinearVelocityFromLocalPoint(localPoint, out) {
return this.GetLinearVelocityFromWorldPoint(this.GetWorldPoint(localPoint, out), out);
}
/**
* Get the linear damping of the body.
*/
GetLinearDamping() {
return this.m_linearDamping;
}
/**
* Set the linear damping of the body.
*/
SetLinearDamping(linearDamping) {
this.m_linearDamping = linearDamping;
}
/**
* Get the angular damping of the body.
*/
GetAngularDamping() {
return this.m_angularDamping;
}
/**
* Set the angular damping of the body.
*/
SetAngularDamping(angularDamping) {
this.m_angularDamping = angularDamping;
}
/**
* Get the gravity scale of the body.
*/
GetGravityScale() {
return this.m_gravityScale;
}
/**
* Set the gravity scale of the body.
*/
SetGravityScale(scale) {
this.m_gravityScale = scale;
}
/**
* Set the type of this body. This may alter the mass and velocity.
*/
SetType(type) {
(0, b2_common_1.b2Assert)(!this.m_world.IsLocked());
if (this.m_type === type) {
return;
}
this.m_type = type;
this.ResetMassData();
if (this.m_type === b2BodyType.b2_staticBody) {
this.m_linearVelocity.SetZero();
this.m_angularVelocity = 0;
this.m_sweep.a0 = this.m_sweep.a;
this.m_sweep.c0.Copy(this.m_sweep.c);
this.m_awakeFlag = false;
this.SynchronizeFixtures();
}
this.SetAwake(true);
this.m_force.SetZero();
this.m_torque = 0;
// Delete the attached contacts.
let ce = this.m_contactList;
while (ce) {
const ce0 = ce;
ce = ce.next;
this.m_world.m_contactManager.Destroy(ce0.contact);
}
this.m_contactList = null;
// Touch the proxies so that new contacts will be created (when appropriate)
const broadPhase = this.m_world.m_contactManager.m_broadPhase;
for (let f = this.m_fixtureList; f; f = f.m_next) {
for (const proxy of f.m_proxies) {
broadPhase.TouchProxy(proxy.treeNode);
}
}
}
/**
* Get the type of this body.
*/
GetType() {
return this.m_type;
}
/**
* Should this body be treated like a bullet for continuous collision detection?
*/
SetBullet(flag) {
this.m_bulletFlag = flag;
}
/**
* Is this body treated like a bullet for continuous collision detection?
*/
IsBullet() {
return this.m_bulletFlag;
}
/**
* You can disable sleeping on this body. If you disable sleeping, the
* body will be woken.
*/
SetSleepingAllowed(flag) {
this.m_autoSleepFlag = flag;
if (!flag) {
this.SetAwake(true);
}
}
/**
* Is this body allowed to sleep
*/
IsSleepingAllowed() {
return this.m_autoSleepFlag;
}
/**
* Set the sleep state of the body. A sleeping body has very
* low CPU cost.
*
* @param flag Set to true to wake the body, false to put it to sleep.
*/
SetAwake(flag) {
if (this.m_type === b2BodyType.b2_staticBody) {
return;
}
if (flag) {
this.m_awakeFlag = true;
this.m_sleepTime = 0;
}
else {
this.m_awakeFlag = false;
this.m_sleepTime = 0;
this.m_linearVelocity.SetZero();
this.m_angularVelocity = 0;
this.m_force.SetZero();
this.m_torque = 0;
}
}
/**
* Get the sleeping state of this body.
*
* @returns true if the body is awake.
*/
IsAwake() {
return this.m_awakeFlag;
}
/**
* Allow a body to be disabled. A disabled body is not simulated and cannot
* be collided with or woken up.
* If you pass a flag of true, all fixtures will be added to the broad-phase.
* If you pass a flag of false, all fixtures will be removed from the
* broad-phase and all contacts will be destroyed.
* Fixtures and joints are otherwise unaffected. You may continue
* to create/destroy fixtures and joints on disabled bodies.
* Fixtures on a disabled body are implicitly disabled and will
* not participate in collisions, ray-casts, or queries.
* Joints connected to a disabled body are implicitly disabled.
* An disabled body is still owned by a b2World object and remains
* in the body list.
*/
SetEnabled(flag) {
(0, b2_common_1.b2Assert)(!this.m_world.IsLocked());
if (flag === this.IsEnabled()) {
return;
}
this.m_enabledFlag = flag;
const broadPhase = this.m_world.m_contactManager.m_broadPhase;
if (flag) {
// Create all proxies.
for (let f = this.m_fixtureList; f; f = f.m_next) {
f.CreateProxies(broadPhase, this.m_xf);
}
// Contacts are created at the beginning of the next
this.m_world.m_newContacts = true;
}
else {
// Destroy all proxies.
for (let f = this.m_fixtureList; f; f = f.m_next) {
f.DestroyProxies(broadPhase);
}
// Destroy the attached contacts.
let ce = this.m_contactList;
while (ce) {
const ce0 = ce;
ce = ce.next;
this.m_world.m_contactManager.Destroy(ce0.contact);
}
this.m_contactList = null;
}
}
/**
* Get the active state of the body.
*/
IsEnabled() {
return this.m_enabledFlag;
}
/**
* Set this body to have fixed rotation. This causes the mass
* to be reset.
*/
SetFixedRotation(flag) {
if (this.m_fixedRotationFlag === flag) {
return;
}
this.m_fixedRotationFlag = flag;
this.m_angularVelocity = 0;
this.ResetMassData();
}
/**
* Does this body have fixed rotation?
*/
IsFixedRotation() {
return this.m_fixedRotationFlag;
}
/**
* Get the list of all fixtures attached to this body.
*/
GetFixtureList() {
return this.m_fixtureList;
}
/**
* Get the list of all joints attached to this body.
*/
GetJointList() {
return this.m_jointList;
}
/**
* Get the list of all contacts attached to this body.
*
* @warning this list changes during the time step and you may
* miss some collisions if you don't use b2ContactListener.
*/
GetContactList() {
return this.m_contactList;
}
/**
* Get the next body in the world's body list.
*/
GetNext() {
return this.m_next;
}
/**
* Get the user data reference that was provided in the body definition.
*/
GetUserData() {
return this.m_userData;
}
/**
* Set the user data. Use this to store your application specific data.
* This is a merge operation. Only specified keys will be overridden.
*/
SetUserData(data) {
Object.assign(this.m_userData, data);
}
/**
* Get the parent world of this body.
*/
GetWorld() {
return this.m_world;
}
/** @internal */
SynchronizeFixtures() {
const broadPhase = this.m_world.m_contactManager.m_broadPhase;
if (this.m_awakeFlag) {
const xf1 = b2Body.SynchronizeFixtures_s_xf1;
xf1.q.Set(this.m_sweep.a0);
b2_math_1.b2Rot.MultiplyVec2(xf1.q, this.m_sweep.localCenter, xf1.p);
b2_math_1.b2Vec2.Subtract(this.m_sweep.c0, xf1.p, xf1.p);
for (let f = this.m_fixtureList; f; f = f.m_next) {
f.Synchronize(broadPhase, xf1, this.m_xf);
}
}
else {
for (let f = this.m_fixtureList; f; f = f.m_next) {
f.Synchronize(broadPhase, this.m_xf, this.m_xf);
}
}
}
/** @internal */
SynchronizeTransform() {
this.m_xf.q.Set(this.m_sweep.a);
b2_math_1.b2Rot.MultiplyVec2(this.m_xf.q, this.m_sweep.localCenter, this.m_xf.p);
b2_math_1.b2Vec2.Subtract(this.m_sweep.c, this.m_xf.p, this.m_xf.p);
}
/**
* This is used to prevent connected bodies from colliding.
* It may lie, depending on the collideConnected flag.
*
* @internal
*/
ShouldCollide(other) {
// At least one body should be dynamic.
if (this.m_type !== b2BodyType.b2_dynamicBody && other.m_type !== b2BodyType.b2_dynamicBody) {
return false;
}
return this.ShouldCollideConnected(other);
}
ShouldCollideConnected(other) {
// Does a joint prevent collision?
for (let jn = this.m_jointList; jn; jn = jn.next) {
if (jn.other === other) {
if (!jn.joint.m_collideConnected) {
return false;
}
}
}
return true;
}
/** @internal */
Advance(alpha) {
// Advance to the new safe time. This doesn't sync the broad-phase.
this.m_sweep.Advance(alpha);
this.m_sweep.c.Copy(this.m_sweep.c0);
this.m_sweep.a = this.m_sweep.a0;
this.m_xf.q.Set(this.m_sweep.a);
b2_math_1.b2Rot.MultiplyVec2(this.m_xf.q, this.m_sweep.localCenter, this.m_xf.p);
b2_math_1.b2Vec2.Subtract(this.m_sweep.c, this.m_xf.p, this.m_xf.p);
}
}
exports.b2Body = b2Body;
b2Body.SetMassData_s_oldCenter = new b2_math_1.b2Vec2();
b2Body.ResetMassData_s_localCenter = new b2_math_1.b2Vec2();
b2Body.ResetMassData_s_oldCenter = new b2_math_1.b2Vec2();
b2Body.ResetMassData_s_massData = new b2_shape_1.b2MassData();
b2Body.SynchronizeFixtures_s_xf1 = new b2_math_1.b2Transform();