Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
120 changes: 97 additions & 23 deletions extensions/box2d.js
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@
var Vector = Array;
var Vector_a2j_Number = Box2D.NVector;
//package structure
if (typeof Box2D === "undefined") Box2D = {};

Check warning on line 99 in extensions/box2d.js

View workflow job for this annotation

GitHub Actions / type-warnings

Type warning - may indicate a bug - ignore if no bug

Type '{}' is missing the following properties from type '{ Collision: { Shapes: {}; }; Common: { Math: {}; }; Dynamics: { Contacts: {}; Controllers: {}; Joints: {}; }; postDefs: any[]; }': Collision, Common, Dynamics, postDefs
if (typeof Box2D.Collision === "undefined") Box2D.Collision = {};
if (typeof Box2D.Collision.Shapes === "undefined")
Box2D.Collision.Shapes = {};
Expand All @@ -113,51 +113,51 @@
Box2D.Collision.IBroadPhase = "Box2D.Collision.IBroadPhase";

function b2AABB() {
b2AABB.b2AABB.apply(this, arguments);

Check warning on line 116 in extensions/box2d.js

View workflow job for this annotation

GitHub Actions / type-warnings

Type warning - may indicate a bug - ignore if no bug

Property 'b2AABB' does not exist on type '(...args: any[]) => void'.
}
Box2D.Collision.b2AABB = b2AABB;

function b2Bound() {
b2Bound.b2Bound.apply(this, arguments);

Check warning on line 121 in extensions/box2d.js

View workflow job for this annotation

GitHub Actions / type-warnings

Type warning - may indicate a bug - ignore if no bug

Property 'b2Bound' does not exist on type '(...args: any[]) => void'.
}
Box2D.Collision.b2Bound = b2Bound;

function b2BoundValues() {
b2BoundValues.b2BoundValues.apply(this, arguments);

Check warning on line 126 in extensions/box2d.js

View workflow job for this annotation

GitHub Actions / type-warnings

Type warning - may indicate a bug - ignore if no bug

Property 'b2BoundValues' does not exist on type '(...args: any[]) => void'.
if (this.constructor === b2BoundValues)
this.b2BoundValues.apply(this, arguments);
}
Box2D.Collision.b2BoundValues = b2BoundValues;

function b2Collision() {
b2Collision.b2Collision.apply(this, arguments);

Check warning on line 133 in extensions/box2d.js

View workflow job for this annotation

GitHub Actions / type-warnings

Type warning - may indicate a bug - ignore if no bug

Property 'b2Collision' does not exist on type '(...args: any[]) => void'.
}
Box2D.Collision.b2Collision = b2Collision;

function b2ContactID() {
b2ContactID.b2ContactID.apply(this, arguments);

Check warning on line 138 in extensions/box2d.js

View workflow job for this annotation

GitHub Actions / type-warnings

Type warning - may indicate a bug - ignore if no bug

Property 'b2ContactID' does not exist on type '(...args: any[]) => void'.
if (this.constructor === b2ContactID)
this.b2ContactID.apply(this, arguments);
}
Box2D.Collision.b2ContactID = b2ContactID;

function b2ContactPoint() {
b2ContactPoint.b2ContactPoint.apply(this, arguments);

Check warning on line 145 in extensions/box2d.js

View workflow job for this annotation

GitHub Actions / type-warnings

Type warning - may indicate a bug - ignore if no bug

Property 'b2ContactPoint' does not exist on type '(...args: any[]) => void'.
}
Box2D.Collision.b2ContactPoint = b2ContactPoint;

function b2Distance() {
b2Distance.b2Distance.apply(this, arguments);

Check warning on line 150 in extensions/box2d.js

View workflow job for this annotation

GitHub Actions / type-warnings

Type warning - may indicate a bug - ignore if no bug

Property 'b2Distance' does not exist on type '(...args: any[]) => void'.
}
Box2D.Collision.b2Distance = b2Distance;

function b2DistanceInput() {
b2DistanceInput.b2DistanceInput.apply(this, arguments);

Check warning on line 155 in extensions/box2d.js

View workflow job for this annotation

GitHub Actions / type-warnings

Type warning - may indicate a bug - ignore if no bug

Property 'b2DistanceInput' does not exist on type '(...args: any[]) => void'.
}
Box2D.Collision.b2DistanceInput = b2DistanceInput;

function b2DistanceOutput() {
b2DistanceOutput.b2DistanceOutput.apply(this, arguments);

Check warning on line 160 in extensions/box2d.js

View workflow job for this annotation

GitHub Actions / type-warnings

Type warning - may indicate a bug - ignore if no bug

Property 'b2DistanceOutput' does not exist on type '(...args: any[]) => void'.
}
Box2D.Collision.b2DistanceOutput = b2DistanceOutput;

Expand Down Expand Up @@ -12897,9 +12897,9 @@
};

const _placeBody = function (id, x, y, dir) {
if (bodies[id]) {
world.DestroyBody(bodies[id]);
}
// Replacing the body destroys its pin, so remember to make a new one.
const wasPinned = !!pinned[id];
_removeBody(id);

fixDef.filter.categoryBits = bodyCategoryBits;
fixDef.filter.maskBits = bodyMaskBits;
Expand All @@ -12912,13 +12912,21 @@
body.uid = id;
body.CreateFixture(fixDef);
bodies[id] = body;

if (wasPinned) {
pinned[id] = _pinBodyToWorld(id);
}
return body;
};

const _removeBody = function (id) {
if (!bodies[id]) return;
const body = bodies[id];
if (!body) return;

world.DestroyBody(bodies[id]);
// Box2D destroys every joint attached to a body along with it, so the pins
// have to be sorted out first or they'd be left dangling in `pinned`.
_releasePinsTo(body);
world.DestroyBody(body);
delete bodies[id];
delete prevPos[id];
};
Expand Down Expand Up @@ -13039,6 +13047,66 @@
return joint;
};

/**
* Pin a sprite where it currently is, holding it against the world rather
* than against some other sprite.
* @param {*} id the target ID of an existing body.
* @returns {?Object} the new joint.
*/
const _pinBodyToWorld = function (id) {
const body = bodies[id];
if (!body) return null;

const pos = body.GetPosition();
return _createJointOfType(
null,
"Rotating",
id,
0,
0,
null,
pos.x * zoom,
pos.y * zoom
);
};

/**
* Deal with the pins that are about to be destroyed along with a body.
* Sprites pinned to it would otherwise silently come loose and start falling,
* so they get pinned to the world in the same place instead.
* @param {!Object} body the body that is about to be destroyed.
*/
const _releasePinsTo = function (body) {
for (const id in pinned) {
const joint = pinned[id];
if (!joint) {
delete pinned[id];
continue;
}
if (joint.GetBodyA() !== body && joint.GetBodyB() !== body) continue;

world.DestroyJoint(joint);
delete pinned[id];
// The body being destroyed loses its own pin for good; anything else
// stays pinned, just to the world from now on.
if (bodies[id] && bodies[id] !== body) {
pinned[id] = _pinBodyToWorld(id);
}
}
};

/**
* Destroy the pin holding a sprite in place, if it has one.
* @param {*} id the target ID.
*/
const _unpinBody = function (id) {
const joint = pinned[id];
if (!joint) return;

world.DestroyJoint(joint);
delete pinned[id];
};

/**
* Set the X and Y coordinates (No Fencing)
* @param {!RenderedTarget} rt the renderedTarget.
Expand Down Expand Up @@ -13167,6 +13235,11 @@
// Clear target motion state values when the project starts.
this.runtime.on("PROJECT_START", this.reset.bind(this));

// Waiting until the next simulation step to notice that a sprite is gone
// would leave its body sitting in the world in the meantime, where new
// sprites can still collide with it or get pinned to it.
this.runtime.on("targetWasRemoved", (target) => _removeBody(target.id));

world = new b2World(
new b2Vec2(0, -10), // gravity (10)
true // allow sleep
Expand All @@ -13185,14 +13258,18 @@

reset() {
for (const body in bodies) {
if (pinned[body]) {
world.DestroyJoint(pinned[body]);
delete pinned[body];
}
// Destroying the body destroys its joints too, so the pins only need
// to be forgotten about, not destroyed a second time.
delete pinned[body];
world.DestroyBody(bodies[body]);
delete bodies[body];
delete prevPos[body];
}
// Pins belonging to sprites that are already gone would otherwise be
// left behind pointing at destroyed joints.
for (const id in pinned) {
delete pinned[id];
}
tickRate = 30;
// todo: delete joins?
}
Expand Down Expand Up @@ -13974,9 +14051,7 @@
const target = this.runtime.getTargetById(targetID);
if (!target) {
// Drop target from simulation
world.DestroyBody(body);
delete bodies[targetID];
delete prevPos[targetID];
_removeBody(targetID);
continue;
}

Expand Down Expand Up @@ -14013,9 +14088,7 @@
const target = this.runtime.getTargetById(targetID);
if (!target) {
// Drop target from simulation
world.DestroyBody(body);
delete bodies[targetID];
delete prevPos[targetID];
_removeBody(targetID);
continue;
}

Expand Down Expand Up @@ -14483,6 +14556,10 @@
fixedRotation ? 0 : (90 - target.direction) * toRad
);

// Whatever the sprite was pinned to before, that pin is replaced here.
// Leaving it in place would stack up joints that nothing destroys.
_unpinBody(target.id);

if (args.static === "pinned") {
// Find what's behind the sprite (pin to that)
const point = new b2AABB();
Expand All @@ -14492,7 +14569,11 @@
world.QueryAABB((fixture) => {
const body2 = fixture.GetBody();
if (body2 !== body && fixture.TestPoint(pos.x, pos.y)) {
body2ID = body2.uid;
// Only sprites can be pinned to. The stage edges have no ID, and
// anything not in `bodies` no longer belongs to the simulation.
if (bodies[body2.uid] === body2) {
body2ID = body2.uid;
}
return false;
}
return true;
Expand All @@ -14508,13 +14589,6 @@
null,
null
);
} else {
const pin = pinned[target.id];
if (pin) {
world.DestroyJoint(pin);
// delete joints[pin.I];
delete pinned[target.id];
}
}
}

Expand Down