From f4ad2fe4ddef8cd2389b695073ed43298a84f5c9 Mon Sep 17 00:00:00 2001 From: Lukas Klingsbo Date: Sun, 7 Sep 2025 17:23:19 +0200 Subject: [PATCH 1/3] fix: Destroy and create bodies after step is done --- packages/forge2d/lib/src/dynamics/world.dart | 23 +++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/packages/forge2d/lib/src/dynamics/world.dart b/packages/forge2d/lib/src/dynamics/world.dart index 4f0b32e..35abd49 100644 --- a/packages/forge2d/lib/src/dynamics/world.dart +++ b/packages/forge2d/lib/src/dynamics/world.dart @@ -25,6 +25,8 @@ class World { late ContactManager contactManager; final List bodies = []; final List joints = []; + final List bodiesToCreate = []; + final List bodiesToDestroy = []; final Vector2 _gravity; @@ -133,8 +135,11 @@ class World { /// /// Warning: This function is locked during callbacks. Body createBody(BodyDef def) { - assert(!isLocked); final body = Body(def, this); + if (isLocked) { + bodiesToCreate.add(body); + return body; + } bodies.add(body); return body; } @@ -145,8 +150,10 @@ class World { /// Warning: This automatically deletes all associated shapes and joints. /// Warning: This function is locked during callbacks. void destroyBody(Body body) { - assert(bodies.isNotEmpty); - assert(!isLocked); + if (isLocked) { + bodiesToDestroy.add(body); + return; + } // Delete the attached joints. while (body.joints.isNotEmpty) { @@ -297,6 +304,16 @@ class World { flags &= ~locked; + for (final body in bodiesToCreate) { + bodies.add(body); + } + bodiesToCreate.clear(); + + for (final body in bodiesToDestroy) { + destroyBody(body); + } + bodiesToDestroy.clear(); + _profile.step.record(_stepTimer.getMilliseconds()); } From d554e0c9a382b95233f2aa3e20798b68e0b5f180 Mon Sep 17 00:00:00 2001 From: Lukas Klingsbo Date: Sun, 7 Sep 2025 18:06:04 +0200 Subject: [PATCH 2/3] Loosen meta constraints --- packages/forge2d/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/forge2d/pubspec.yaml b/packages/forge2d/pubspec.yaml index 271b98b..6206a94 100644 --- a/packages/forge2d/pubspec.yaml +++ b/packages/forge2d/pubspec.yaml @@ -8,7 +8,7 @@ environment: sdk: ">=3.8.0 <4.0.0" dependencies: - meta: ^1.17.0 + meta: ^1.16.0 vector_math: ^2.2.0 web: ^1.1.1 From d0682a100758421b3bc6c8fb874afeefdf5cb94a Mon Sep 17 00:00:00 2001 From: Lukas Klingsbo Date: Sun, 7 Sep 2025 19:02:00 +0200 Subject: [PATCH 3/3] Also check joints --- .../src/collision/broadphase/dynamic_tree.dart | 2 +- .../lib/src/dynamics/contact_manager.dart | 11 +++++------ packages/forge2d/lib/src/dynamics/world.dart | 18 +++++++++++------- 3 files changed, 17 insertions(+), 14 deletions(-) diff --git a/packages/forge2d/lib/src/collision/broadphase/dynamic_tree.dart b/packages/forge2d/lib/src/collision/broadphase/dynamic_tree.dart index ea87f02..cee92a5 100644 --- a/packages/forge2d/lib/src/collision/broadphase/dynamic_tree.dart +++ b/packages/forge2d/lib/src/collision/broadphase/dynamic_tree.dart @@ -461,7 +461,7 @@ class DynamicTree implements BroadPhaseStrategy { /// returns a node to the pool void _freeNode(DynamicTreeNode node) { - assert(0 < _nodeCount); + assert(_nodeCount > 0); node.parent = _freeList != nullNode ? _nodes[_freeList] : null; node.height = -1; _freeList = node.id; diff --git a/packages/forge2d/lib/src/dynamics/contact_manager.dart b/packages/forge2d/lib/src/dynamics/contact_manager.dart index 20b8cc4..995d64c 100644 --- a/packages/forge2d/lib/src/dynamics/contact_manager.dart +++ b/packages/forge2d/lib/src/dynamics/contact_manager.dart @@ -6,12 +6,11 @@ class ContactManager implements PairCallback { final Collision collision; final Distance distance; final List contacts = []; - ContactFilter? contactFilter; + ContactFilter contactFilter; ContactListener? contactListener; - ContactManager(this.broadPhase, this.collision, this.distance) { - contactFilter = ContactFilter(); - } + ContactManager(this.broadPhase, this.collision, this.distance) + : contactFilter = ContactFilter(); /// Broad-phase callback. @override @@ -49,7 +48,7 @@ class ContactManager implements PairCallback { } // Check user filtering. - if (contactFilter?.shouldCollide(fixtureA, fixtureB) == false) { + if (contactFilter.shouldCollide(fixtureA, fixtureB) == false) { return; } @@ -122,7 +121,7 @@ class ContactManager implements PairCallback { } // Check user filtering. - if (contactFilter?.shouldCollide(fixtureA, fixtureB) == false) { + if (contactFilter.shouldCollide(fixtureA, fixtureB) == false) { contactRemovals.add(c); continue; } diff --git a/packages/forge2d/lib/src/dynamics/world.dart b/packages/forge2d/lib/src/dynamics/world.dart index 35abd49..935a6a9 100644 --- a/packages/forge2d/lib/src/dynamics/world.dart +++ b/packages/forge2d/lib/src/dynamics/world.dart @@ -27,6 +27,8 @@ class World { final List joints = []; final List bodiesToCreate = []; final List bodiesToDestroy = []; + final List jointsToCreate = []; + final List jointsToDestroy = []; final Vector2 _gravity; @@ -39,7 +41,7 @@ class World { /// /// See also: /// - /// * [Body.gravityScale], to multipy [gravity] for a [Body]. + /// * [Body.gravityScale], to multiply [gravity] for a [Body]. /// * [Body.gravityOverride], to change how the world treats the gravity for /// a [Body]. /// {@endtemplate} @@ -180,10 +182,11 @@ class World { /// This may cause the connected bodies to cease colliding. /// /// Adding a joint doesn't wake up the bodies. - /// - /// Warning: This function is locked during callbacks. void createJoint(Joint joint) { - assert(!isLocked); + if (isLocked) { + jointsToCreate.add(joint); + return; + } joints.add(joint); final bodyA = joint.bodyA; @@ -204,10 +207,11 @@ class World { } /// Destroys a joint. This may cause the connected bodies to begin colliding. - /// - /// Warning: This function is locked during callbacks. void destroyJoint(Joint joint) { - assert(!isLocked); + if (isLocked) { + jointsToDestroy.add(joint); + return; + } final collideConnected = joint.collideConnected; joints.remove(joint);