Skip to content
Merged
Show file tree
Hide file tree
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
34 changes: 22 additions & 12 deletions packages/forge2d/lib/src/dynamics/world.dart
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,10 @@ class World {
late ContactManager contactManager;
final List<Body> bodies = <Body>[];
final List<Joint> joints = <Joint>[];
final List<Body> bodiesToCreate = <Body>[];
final List<Body> bodiesToDestroy = <Body>[];
final List<Joint> jointsToCreate = <Joint>[];
final List<Joint> jointsToDestroy = <Joint>[];
final List<Body> _bodiesToCreate = <Body>[];
final List<Body> _bodiesToDestroy = <Body>[];
final List<Joint> _jointsToCreate = <Joint>[];
final List<Joint> _jointsToDestroy = <Joint>[];

final Vector2 _gravity;

Expand Down Expand Up @@ -139,7 +139,7 @@ class World {
Body createBody(BodyDef def) {
final body = Body(def, this);
if (isLocked) {
bodiesToCreate.add(body);
_bodiesToCreate.add(body);
return body;
}
bodies.add(body);
Expand All @@ -153,7 +153,7 @@ class World {
/// Warning: This function is locked during callbacks.
void destroyBody(Body body) {
if (isLocked) {
bodiesToDestroy.add(body);
_bodiesToDestroy.add(body);
return;
}

Expand Down Expand Up @@ -184,7 +184,7 @@ class World {
/// Adding a joint doesn't wake up the bodies.
void createJoint(Joint joint) {
if (isLocked) {
jointsToCreate.add(joint);
_jointsToCreate.add(joint);
return;
}
joints.add(joint);
Expand All @@ -209,7 +209,7 @@ class World {
/// Destroys a joint. This may cause the connected bodies to begin colliding.
void destroyJoint(Joint joint) {
if (isLocked) {
jointsToDestroy.add(joint);
_jointsToDestroy.add(joint);
return;
}

Expand Down Expand Up @@ -308,15 +308,25 @@ class World {

flags &= ~locked;

for (final body in bodiesToCreate) {
for (final body in _bodiesToCreate) {
bodies.add(body);
}
bodiesToCreate.clear();
_bodiesToCreate.clear();

for (final body in bodiesToDestroy) {
for (final body in _bodiesToDestroy) {
destroyBody(body);
}
bodiesToDestroy.clear();
_bodiesToDestroy.clear();

for (final joint in _jointsToCreate) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

did this just... never worked? haha

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Haha yeah, but it's quite new

createJoint(joint);
}
_jointsToCreate.clear();

for (final joint in _jointsToDestroy) {
destroyJoint(joint);
}
_jointsToDestroy.clear();

_profile.step.record(_stepTimer.getMilliseconds());
}
Expand Down
29 changes: 29 additions & 0 deletions packages/forge2d/test/dynamics/body_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -83,5 +83,34 @@ void main() {
expect(bodyInitialPosition.y, isNot(equals(body.position.y)));
});
});

test('creation and destruction of body while world is locked', () {
final world = World(Vector2(0.0, -10.0));
final bodyDef = BodyDef();

world.flags = World.locked;

// Attempt to create a body while the world is locked
final body = world.createBody(bodyDef);
expect(world.bodies.contains(body), isFalse);

world.flags = 0;
world.stepDt(1 / 60);

// Verify the body is created after unlocking the world
expect(world.bodies.contains(body), isTrue);

world.flags = World.locked;

// Attempt to destroy the body while the world is locked
world.destroyBody(body);
expect(world.bodies.contains(body), isTrue);

world.flags = 0;
world.stepDt(1 / 60);

// Verify the body is destroyed after unlocking the world
expect(world.bodies.contains(body), isFalse);
});
});
}
47 changes: 47 additions & 0 deletions packages/forge2d/test/dynamics/joints/joint_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -39,5 +39,52 @@ void main() {
expect(body1.joints.length, 0);
expect(body2.joints.length, 0);
});

test('destruction of body with joint while world is locked', () {
final world = World(Vector2(0.0, -10.0));
final bodyDef = BodyDef();
final body1 = world.createBody(bodyDef);
final body2 = world.createBody(bodyDef..position = Vector2.all(2));
final shape = CircleShape(radius: 1.2, position: Vector2.all(10));
final fixtureDef = FixtureDef(
shape,
density: 50.0,
friction: 0.1,
restitution: 0.9,
);

body1.createFixture(fixtureDef);
body2.createFixture(fixtureDef);

world.flags = World.locked;

final revoluteJointDef = RevoluteJointDef()
..initialize(body1, body2, body1.position);
final revoluteJoint = RevoluteJoint(revoluteJointDef);
world.createJoint(revoluteJoint);

expect(body1.joints.length, 0);
expect(body2.joints.length, 0);

world.flags = 0;
world.stepDt(1 / 60);

expect(body1.joints.length, 1);
expect(body2.joints.length, 1);

world.flags = World.locked;

// Attempt to destroy the body while the world is locked
world.destroyBody(body1);
expect(body1.joints.length, 1);
expect(body2.joints.length, 1);

// Step the world again to process the destruction
world.flags = 0;
world.stepDt(1 / 60);

expect(body1.joints.length, 0);
expect(body2.joints.length, 0);
});
});
}