My game exposes some user-configurable settings. If these settings change then I need to recreate it. The game is the majority of the code in my app, but things like "main menu" aren't part of the game itself.
Prior to this, I was writing code like:
pub struct MyPlugin;
impl Plugin for MyPlugin {
fn build(&self, app: &mut App) {
app.init_resource::<MyResource>();
}
}
I felt this was fine because there was a 1:1 relationship between App and Game.
Now that I wish to recreate the game with new settings, and having introduced a main menu to allow the user to define settings before creating a game, I have broken that expectation. There is now a 1:(0 or 1) relationship between App and Game.
I am left with a couple of options to manage my app state:
- Query for MyResource and manually reset it to its default value. The resource continues to exist in the app.
- Remove MyResource from the app in a teardown step. Add MyResource to the app in a setup step.
I dislike the first approach. It seems counter-intuitive because resetting to default, rather than destroy/recreate, feels like it isn't reflective of the fact a game is being destroyed and recreated within the app.
I dislike the second approach because it requires me to call init_resource and remove_resource using systems rather than making use of Plugin architecture.
Additionally, I dislike both approaches because I have to do a lot manually. I feel like there's a hierarchy here of "App" containing "Instance of Game" which is created with "Settings." I wish to destroy "Instance of Game" and recreate with new "Settings." It's effortful and error prone for me to iterate through all entities/resources that are part of "Game" not "App" and manage their lifecycles. I wish to destroy "Game" and have all of its related entities cleaned up.
If this were just components then I would be make use of parent/child + despawn_recursive, but I've already done that. This is all the related resources.
I've been going with the second approach for now. I am wondering if this seems correct? I don't see many examples of this being done when I look at other codebases.
pub fn setup_game_time(world: &mut World) {
world.init_resource::<GameTime>();
world.init_resource::<IsFastForwarding>();
world.init_resource::<PendingTicks>();
}
pub fn teardown_game_time(world: &mut World) {
world.remove_resource::<GameTime>();
world.remove_resource::<IsFastForwarding>();
world.remove_resource::<PendingTicks>();
}
app.add_systems(
OnEnter(StoryState::Initializing),
setup_game_time
);
app.add_systems(
OnEnter(StoryState::Cleanup),
teardown_game_time
);
I also want to confirm that this isn't where the notion of a "SubApp" would come into play, right? I assume not.