Skip to content

Commit

Permalink
Add world.queueUpdate
Browse files Browse the repository at this point in the history
  • Loading branch information
shakiba authored Dec 24, 2024
1 parent 5b611d7 commit f0127f4
Show file tree
Hide file tree
Showing 9 changed files with 92 additions and 46 deletions.
5 changes: 5 additions & 0 deletions .changeset/sour-news-float.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"planck": minor
---

Add world.queueUpdate() to queue and defer updates after current simulation step
10 changes: 5 additions & 5 deletions example/8-Ball.ts
Original file line number Diff line number Diff line change
Expand Up @@ -221,13 +221,13 @@ class BilliardPhysics {
const ball = fA.getUserData() === BALL ? bA : fB.getUserData() === BALL ? bB : null;
const pocket = fA.getUserData() === POCKET ? bA : fB.getUserData() === POCKET ? bB : null;

// do not change world immediately
setTimeout(() => {
if (ball && pocket) {
if (ball && pocket) {
// do not change world immediately
this.world.queueUpdate(() => {
this.world.destroyBody(ball);
this.client?.onBallInPocket(ball, pocket);
}
}, 1);
});
}
};
}

Expand Down
16 changes: 10 additions & 6 deletions example/Asteroid.ts
Original file line number Diff line number Diff line change
Expand Up @@ -230,15 +230,19 @@ class AsteroidPhysics {

const asteroid = dataA?.type == "asteroid" ? bodyA : dataB?.type == "asteroid" ? bodyB : null;

setTimeout(() => {
if (ship && asteroid) {
if (ship && asteroid) {
// do not change world immediately
this.world.queueUpdate(() => {
this.client?.collideShipAsteroid(ship, asteroid);
}
});
}

if (bullet && asteroid) {
if (bullet && asteroid) {
// do not change world immediately
this.world.queueUpdate(() => {
this.client?.collideBulletAsteroid(bullet, asteroid);
}
}, 1);
});
}
}

deleteShip(): boolean {
Expand Down
8 changes: 3 additions & 5 deletions example/Breakable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,14 +53,12 @@ world.on("post-solve", function (contact, impulse) {
}

if (maxImpulse > 40.0) {
setTimeout(function () {
Break();
broke = true;
});
broke = true;
world.queueUpdate(breakIt);
}
});

function Break() {
function breakIt() {
// Create two bodies from one.
const center = body1.getWorldCenter();

Expand Down
24 changes: 16 additions & 8 deletions example/Breakout.ts
Original file line number Diff line number Diff line change
Expand Up @@ -198,19 +198,27 @@ class BreakoutPhysics {
const drop = typeA === "drop" ? dataA : typeB === "drop" ? dataB : null;

// do not change world immediately
setTimeout(() => {
if (ball && brick) {
if (ball && brick) {
this.world.queueUpdate(() => {
this.client?.collideBallBrick(ball as BallData, brick as BrickData);
} else if (ball && bottom) {
});
} else if (ball && bottom) {
this.world.queueUpdate(() => {
this.client?.collideBallBottom(ball as BallData);
} else if (ball && paddle) {
});
} else if (ball && paddle) {
this.world.queueUpdate(() => {
this.client?.collideBallPaddle(ball as BallData);
} else if (drop && paddle) {
});
} else if (drop && paddle) {
this.world.queueUpdate(() => {
this.client?.collideDropPaddle(drop as DropData);
} else if (drop && bottom) {
});
} else if (drop && bottom) {
this.world.queueUpdate(() => {
this.client?.collideDropBottom(drop as DropData);
}
}, 1);
});
}
};

createBoardPhysics() {
Expand Down
9 changes: 4 additions & 5 deletions example/Shuffle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,12 +87,11 @@ world.on("post-solve", function (contact) {
? bB
: null;

// do not change world immediately
setTimeout(function () {
if (ball && wall) {
if (ball && wall) {
world.queueUpdate(() => {
world.destroyBody(ball);
}
}, 1);
});
}
});

function row(n: number, m: number, r: number, l: number) {
Expand Down
10 changes: 5 additions & 5 deletions example/Soccer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,14 +131,14 @@ world.on("post-solve", function (contact) {
? bB
: null;

// do not change world immediately
setTimeout(function () {
if (ball && goal) {
if (ball && goal) {
// do not change world immediately
world.queueUpdate(function () {
ball.setPosition({ x: 0, y: 0 });
ball.setLinearVelocity({ x: 0, y: 0 });
// world.destroyBody(ball);
}
}, 1);
});
}
});

function team() {
Expand Down
16 changes: 13 additions & 3 deletions src/dynamics/Body.ts
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,8 @@ export class Body {
/**
* Set the type of the body to "static", "kinematic" or "dynamic".
* @param type The type of the body.
*
* Warning: This function is locked when a world simulation step is in progress. Use queueUpdate to schedule a function to be called after the step.
*/
setType(type: BodyType): void {
if (_ASSERT) console.assert(type === STATIC || type === KINEMATIC || type === DYNAMIC);
Expand Down Expand Up @@ -502,6 +504,8 @@ export class Body {
* in collisions, ray-casts, or queries. Joints connected to an inactive body
* are implicitly inactive. An inactive body is still owned by a World object
* and remains
*
* Warning: This function is locked when a world simulation step is in progress. Use queueUpdate to schedule a function to be called after the step.
*/
setActive(flag: boolean): void {
if (_ASSERT) console.assert(this.isWorldLocked() == false);
Expand Down Expand Up @@ -568,6 +572,8 @@ export class Body {
* Set the position of the body's origin and rotation. Manipulating a body's
* transform may cause non-physical behavior. Note: contacts are updated on the
* next call to World.step.
*
* Warning: This function is locked when a world simulation step is in progress. Use queueUpdate to schedule a function to be called after the step.
*
* @param position The world position of the body's local origin.
* @param angle The world rotation in radians.
Expand All @@ -577,6 +583,8 @@ export class Body {
* Set the position of the body's origin and rotation. Manipulating a body's
* transform may cause non-physical behavior. Note: contacts are updated on the
* next call to World.step.
*
* Warning: This function is locked when a world simulation step is in progress. Use queueUpdate to schedule a function to be called after the step.
*/
setTransform(xf: Transform): void;
setTransform(a: Vec2Value | Transform, b?: number): void {
Expand Down Expand Up @@ -863,6 +871,8 @@ export class Body {
* 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.
*
* Warning: This function is locked when a world simulation step is in progress. Use queueUpdate to schedule a function to be called after the step.
*
* @param massData The mass properties.
*/
Expand Down Expand Up @@ -1068,7 +1078,7 @@ export class Body {
*
* Contacts are not created until the next time step.
*
* Warning: This function is locked during callbacks.
* Warning: This function is locked when a world simulation step is in progress. Use queueUpdate to schedule a function to be called after the step.
*/
createFixture(def: FixtureDef): Fixture;
createFixture(shape: Shape, opt?: FixtureOpt): Fixture;
Expand All @@ -1092,8 +1102,8 @@ export class Body {
* 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.
*
* Warning: This function is locked during callbacks.
*
* Warning: This function is locked when a world simulation step is in progress. Use queueUpdate to schedule a function to be called after the step.
*
* @param fixture The fixture to be removed.
*/
Expand Down
40 changes: 31 additions & 9 deletions src/dynamics/World.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,8 @@ export class World {
/** @internal */ m_positionIterations: number;
/** @internal */ m_t: number;

/** @internal */ m_step_callback: ((world: World) => unknown)[] = [];

// TODO
/** @internal */ _listeners: {
[key: string]: any[]
Expand Down Expand Up @@ -469,10 +471,12 @@ export class World {
* position -= newOrigin
*
* @param newOrigin The new origin with respect to the old origin
*
* Warning: This function is locked when a world simulation step is in progress. Use queueUpdate to schedule a function to be called after the step.
*/
shiftOrigin(newOrigin: Vec2Value): void {
if (_ASSERT) console.assert(this.m_locked == false);
if (this.m_locked) {
if (_ASSERT) console.assert(this.isLocked() == false);
if (this.isLocked()) {
return;
}

Expand Down Expand Up @@ -510,7 +514,7 @@ export class World {
* Create a rigid body given a definition. No reference to the definition is
* retained.
*
* Warning: This function is locked during callbacks.
* Warning: This function is locked when a world simulation step is in progress. Use queueUpdate to schedule a function to be called after the step.
*/
createBody(def?: BodyDef): Body;
createBody(position: Vec2Value, angle?: number): Body;
Expand Down Expand Up @@ -565,12 +569,11 @@ export class World {
}

/**
* Destroy a rigid body given a definition. No reference to the definition is
* retained.
* Destroy a body from the world.
*
* Warning: This automatically deletes all associated shapes and joints.
*
* Warning: This function is locked during callbacks.
* Warning: This function is locked when a world simulation step is in progress. Use queueUpdate to schedule a function to be called after the step.
*/
destroyBody(b: Body): boolean {
if (_ASSERT) console.assert(this.m_bodyCount > 0);
Expand Down Expand Up @@ -647,7 +650,7 @@ export class World {
* Create a joint to constrain bodies together. No reference to the definition
* is retained. This may cause the connected bodies to cease colliding.
*
* Warning: This function is locked during callbacks.
* Warning: This function is locked when a world simulation step is in progress. Use queueUpdate to schedule a function to be called after the step.
*/
createJoint<T extends Joint>(joint: T): T | null {
if (_ASSERT) console.assert(!!joint.m_bodyA);
Expand Down Expand Up @@ -700,8 +703,11 @@ export class World {
}

/**
* Destroy a joint. This may cause the connected bodies to begin colliding.
* Warning: This function is locked during callbacks.
* Destroy a joint.
*
* Warning: This may cause the connected bodies to begin colliding.
*
* Warning: This function is locked when a world simulation step is in progress. Use queueUpdate to schedule a function to be called after the step.
*/
destroyJoint(joint: Joint): void {
if (_ASSERT) console.assert(this.isLocked() == false);
Expand Down Expand Up @@ -854,9 +860,25 @@ export class World {

this.m_locked = false;

let callback: (world: World) => unknown;
while(callback = this.m_step_callback.pop()) {
callback(this);
}

this.publish("post-step", timeStep);
}

/**
* Queue a function to be called after ongoing simulation step. If no simulation is in progress call it immediately.
*/
queueUpdate(callback: (world: World) => unknown): void {
if (!this.isLocked()) {
callback(this);
} else {
this.m_step_callback.push(callback);
}
}

/**
* @internal
* Call this method to find new contacts.
Expand Down

0 comments on commit f0127f4

Please sign in to comment.