-
-
Notifications
You must be signed in to change notification settings - Fork 1k
Description
What happened?
Hello,
I'm encountering an issue when using RouterComponent with WorldRoute in a flame_forge2d project.
Specifically, when transitioning between routes (e.g., from a WorldRoute to an OverlayRoute using replace),
I get the following assertion error:
The following assertion was thrown during a scheduler callback:
'package:forge2d/src/dynamics/world.dart': Failed assertion: line 148 pos 12: 'bodies.isNotEmpty': is not true.
When the exception was thrown, this was the stack:
#2 World.destroyBody (package:forge2d/src/dynamics/world.dart:148:12)
#3 Forge2DWorld.destroyBody (package:flame_forge2d/forge2d_world.dart:31:18)
#4 BodyComponent.onRemove (package:flame_forge2d/body_component.dart:217:11)
context
My game uses RouterComponent to manage navigation between different screens, including a start screen (OverlayRoute), a main game world (WorldRoute), a dungeon world (WorldRoute), and a config dialog (OverlayRoute). Below is an example of my router setup:
RouterComponent(
routes: {
RouteType.start.name: OverlayRoute((context, _) {
return StartScreenWidget(game: game);
}),
RouteType.main.name: WorldRoute(
() => MainWorld(),
maintainState: false,
),
RouteType.dungeon.name: WorldRoute(
() => DungeonWorld(),
maintainState: false,
),
RouteType.configDialog.name: OverlayRoute((context, _) {
return ConfigDialogWidget(game: game);
}),
},
initialRoute: RouteType.start.name,
);The error occurs when replacing a WorldRoute (e.g., main or dungeon) with another route (e.g., start) using router.replaceNamed. It appears that BodyComponent instances added to the current WorldRoute are not removed immediately. Instead, their removal seems to be queued via root.enqueueRemove(), and their onRemove method (which calls world.destroyBody(body)) is invoked after the router has already switched to a new World.
Temporary Workaround
As a temporary fix, I explicitly remove all BodyComponent instances before the route transition and added a 1-second delay to ensure the components are fully removed:
void clearGameBodies() {
final components = game.world.children.whereType<BodyComponent>().toList();
for (final component in components) {
component.removeFromParent();
}
}
Future<void> pushReplacementOverlay(String routeName) async {
clearGameBodies();
await Future.delayed(Duration(seconds: 1)); // Wait for removal
router.replaceNamed(routeName); // OK
}This workaround prevents the assertion error, but it feels like a suboptimal solution due to the arbitrary delay.
- Is the combination of RouterComponent and flame_forge2d with WorldRoute inherently problematic due to the timing of World replacement and BodyComponent removal?
- What is the recommended approach to handle route transitions with WorldRoute to avoid this assertion error? Should I manually clean up bodies in the World before switching routes, or is there a better way to synchronize BodyComponent removal with World transitions?
What do you expect?
I would ideally expect route transitions in flame_forge2d using WorldRoute to work seamlessly without requiring special handling. Specifically, it would be great if switching between routes (e.g., from a WorldRoute to another route) automatically manages the cleanup of BodyComponent instances and their associated Body objects in the Forge2DWorld, preventing assertion errors like assert(bodies.isNotEmpty) without manual intervention.
How can we reproduce this?
No response
What steps should take to fix this?
No response
Do have an example of where the bug occurs?
No response
Relevant log output
Execute in a terminal and put output into the code block below
Output of: flutter doctor -v
Affected platforms
Android
Other information
No response
Are you interested in working on a PR for this?
- I want to work on this