@box2d/debug-draw
Version:
Debug drawing helper for @box2d
324 lines (323 loc) • 11.7 kB
JavaScript
"use strict";
// MIT License
Object.defineProperty(exports, "__esModule", { value: true });
exports.b2Fixture = exports.b2FixtureProxy = exports.b2DefaultFilter = 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_collision_1 = require("../collision/b2_collision");
const b2_shape_1 = require("../collision/b2_shape");
const b2_common_1 = require("../common/b2_common");
const b2_settings_1 = require("../common/b2_settings");
const temp = {
c1: new b2_math_1.b2Vec2(),
c2: new b2_math_1.b2Vec2(),
};
exports.b2DefaultFilter = {
categoryBits: 0x0001,
maskBits: 0xffff,
groupIndex: 0,
};
/**
* This proxy is used internally to connect fixtures to the broad-phase.
*/
class b2FixtureProxy {
constructor(fixture, broadPhase, xf, childIndex) {
this.aabb = new b2_collision_1.b2AABB();
this.fixture = fixture;
this.childIndex = childIndex;
fixture.m_shape.ComputeAABB(this.aabb, xf, childIndex);
this.treeNode = broadPhase.CreateProxy(this.aabb, this);
}
}
exports.b2FixtureProxy = b2FixtureProxy;
const Synchronize_s_aabb1 = new b2_collision_1.b2AABB();
const Synchronize_s_aabb2 = new b2_collision_1.b2AABB();
const Synchronize_s_displacement = new b2_math_1.b2Vec2();
/**
* A fixture is used to attach a shape to a body for collision detection. A fixture
* inherits its transform from its parent. Fixtures hold additional non-geometric data
* such as friction, collision filters, etc.
* Fixtures are created via b2Body::CreateFixture.
*
* @warning you cannot reuse fixtures.
*/
class b2Fixture {
/** @internal protected */
get m_proxyCount() {
return this.m_proxies.length;
}
/** @internal protected */
constructor(body, def) {
var _a, _b, _c, _d, _e;
/** @internal protected */
this.m_density = 0;
/** @internal protected */
this.m_next = null;
/** @internal protected */
this.m_friction = 0;
/** @internal protected */
this.m_restitution = 0;
/** @internal protected */
this.m_restitutionThreshold = 0;
/** @internal protected */
this.m_proxies = [];
/** @internal protected */
this.m_isSensor = false;
this.m_userData = {};
this.m_body = body;
this.m_shape = def.shape.Clone();
if (def.userData)
this.SetUserData(def.userData);
this.m_friction = (_a = def.friction) !== null && _a !== void 0 ? _a : 0.2;
this.m_restitution = (_b = def.restitution) !== null && _b !== void 0 ? _b : 0;
this.m_restitutionThreshold = (_c = def.restitutionThreshold) !== null && _c !== void 0 ? _c : b2_settings_1.b2_lengthUnitsPerMeter;
this.m_filter = {
...exports.b2DefaultFilter,
...def.filter,
};
this.m_isSensor = (_d = def.isSensor) !== null && _d !== void 0 ? _d : false;
this.m_density = (_e = def.density) !== null && _e !== void 0 ? _e : 0;
}
/**
* Get the type of the child shape. You can use this to down cast to the concrete shape.
*
* @returns The shape type.
*/
GetType() {
return this.m_shape.GetType();
}
/**
* Get the child shape. You can modify the child shape, however you should not change the
* number of vertices because this will crash some collision caching mechanisms.
* Manipulating the shape may lead to non-physical behavior.
*/
GetShape() {
return this.m_shape;
}
/**
* Set if this fixture is a sensor.
*/
SetSensor(sensor) {
if (sensor !== this.m_isSensor) {
this.m_body.SetAwake(true);
this.m_isSensor = sensor;
}
}
/**
* Is this fixture a sensor (non-solid)?
*
* @returns The true if the shape is a sensor.
*/
IsSensor() {
return this.m_isSensor;
}
/**
* Set the contact filtering data. This will not update contacts until the next time
* step when either parent body is active and awake.
* This automatically calls Refilter.
*/
SetFilterData(filter) {
var _a, _b, _c;
this.m_filter.categoryBits = (_a = filter.categoryBits) !== null && _a !== void 0 ? _a : exports.b2DefaultFilter.categoryBits;
this.m_filter.groupIndex = (_b = filter.groupIndex) !== null && _b !== void 0 ? _b : exports.b2DefaultFilter.groupIndex;
this.m_filter.maskBits = (_c = filter.maskBits) !== null && _c !== void 0 ? _c : exports.b2DefaultFilter.maskBits;
this.Refilter();
}
/**
* Get the contact filtering data.
*/
GetFilterData() {
return this.m_filter;
}
/**
* Call this if you want to establish collision that was previously disabled by b2ContactFilter::ShouldCollide.
*/
Refilter() {
// Flag associated contacts for filtering.
let edge = this.m_body.GetContactList();
while (edge) {
const { contact } = edge;
const fixtureA = contact.GetFixtureA();
const fixtureB = contact.GetFixtureB();
if (fixtureA === this || fixtureB === this) {
contact.FlagForFiltering();
}
edge = edge.next;
}
const world = this.m_body.GetWorld();
// Touch each proxy so that new pairs may be created
const broadPhase = world.m_contactManager.m_broadPhase;
for (const proxy of this.m_proxies) {
broadPhase.TouchProxy(proxy.treeNode);
}
}
/**
* Get the parent body of this fixture.
*
* @returns The parent body.
*/
GetBody() {
return this.m_body;
}
/**
* Get the next fixture in the parent body's fixture list.
*
* @returns The next shape.
*/
GetNext() {
return this.m_next;
}
/**
* Get the user data that was assigned in the fixture definition. Use this to
* store your application specific data.
*/
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);
}
/**
* Test a point for containment in this fixture.
*
* @param p A point in world coordinates.
*/
TestPoint(p) {
return this.m_shape.TestPoint(this.m_body.GetTransform(), p);
}
/**
* Cast a ray against this shape.
*
* @param output The ray-cast results.
* @param input The ray-cast input parameters.
*/
RayCast(output, input, childIndex) {
return this.m_shape.RayCast(output, input, this.m_body.GetTransform(), childIndex);
}
/**
* Get the mass data for this fixture. The mass data is based on the density and
* the shape. The rotational inertia is about the shape's origin. This operation
* may be expensive.
*/
GetMassData(massData = new b2_shape_1.b2MassData()) {
this.m_shape.ComputeMass(massData, this.m_density);
return massData;
}
/**
* Set the density of this fixture. This will _not_ automatically adjust the mass
* of the body. You must call b2Body::ResetMassData to update the body's mass.
*/
SetDensity(density) {
// DEBUG: b2Assert(Number.isFinite(density) && density >= 0);
this.m_density = density;
}
/**
* Get the density of this fixture.
*/
GetDensity() {
return this.m_density;
}
/**
* Get the coefficient of friction.
*/
GetFriction() {
return this.m_friction;
}
/**
* Set the coefficient of friction. This will _not_ change the friction of
* existing contacts.
*/
SetFriction(friction) {
this.m_friction = friction;
}
/**
* Get the coefficient of restitution.
*/
GetRestitution() {
return this.m_restitution;
}
/**
* Set the coefficient of restitution. This will _not_ change the restitution of
* existing contacts.
*/
SetRestitution(restitution) {
this.m_restitution = restitution;
}
/** Get the restitution velocity threshold. */
GetRestitutionThreshold() {
return this.m_restitutionThreshold;
}
/**
* Set the restitution threshold. This will _not_ change the restitution threshold of
* existing contacts.
*/
SetRestitutionThreshold(threshold) {
this.m_restitutionThreshold = threshold;
}
/**
* Get the fixture's AABB. This AABB may be enlarge and/or stale.
* If you need a more accurate AABB, compute it using the shape and
* the body transform.
*/
GetAABB(childIndex) {
// DEBUG: b2Assert(0 <= childIndex && childIndex < this.m_proxyCount);
return this.m_proxies[childIndex].aabb;
}
/**
* These support body activation/deactivation.
*
* @internal protected
*/
CreateProxies(broadPhase, xf) {
(0, b2_common_1.b2Assert)(this.m_proxies.length === 0);
// Create proxies in the broad-phase.
this.m_proxies.length = this.m_shape.GetChildCount();
for (let i = 0; i < this.m_proxies.length; ++i) {
this.m_proxies[i] = new b2FixtureProxy(this, broadPhase, xf, i);
}
}
/** @internal protected */
DestroyProxies(broadPhase) {
// Destroy proxies in the broad-phase.
for (const proxy of this.m_proxies) {
broadPhase.DestroyProxy(proxy.treeNode);
}
this.m_proxies.length = 0;
}
/** @internal protected */
Synchronize(broadPhase, transform1, transform2) {
const { c1, c2 } = temp;
const displacement = Synchronize_s_displacement;
for (const proxy of this.m_proxies) {
// Compute an AABB that covers the swept shape (may miss some rotation effect).
const aabb1 = Synchronize_s_aabb1;
const aabb2 = Synchronize_s_aabb2;
this.m_shape.ComputeAABB(aabb1, transform1, proxy.childIndex);
this.m_shape.ComputeAABB(aabb2, transform2, proxy.childIndex);
proxy.aabb.Combine2(aabb1, aabb2);
b2_math_1.b2Vec2.Subtract(aabb2.GetCenter(c2), aabb1.GetCenter(c1), displacement);
broadPhase.MoveProxy(proxy.treeNode, proxy.aabb, displacement);
}
}
}
exports.b2Fixture = b2Fixture;