bevyengine / bevy

A refreshingly simple data-driven game engine built in Rust
https://bevyengine.org
Apache License 2.0
36.2k stars 3.57k forks source link

Rename `StateScoped` to `StateExitDespawn`, add the inverse variant `StateEntryDespawn` #15849

Open Jaso333 opened 1 month ago

Jaso333 commented 1 month ago

What problem does this solve or what need does it fill?

The current naming of the StateScoped component is slightly misleading: it could be interpreted as "this entity will not exist outside of this state". Whereas in fact it merely despawns on exit of the given state, it doesn't care if you spawn an entity outside of the given state:

for (entity, binding) in &query {
    if binding.0 == *exited {
        #[cfg(feature = "bevy_hierarchy")]
        commands.entity(entity).despawn_recursive();
        #[cfg(not(feature = "bevy_hierarchy"))]
        commands.entity(entity).despawn();
    }
}

To me, this functionality is fine, I can't think of a situation where you would want to spawn something in a state it doesn't belong, only for it to be deleted instantly.

There is also no available inverse of this component: despawn an entity on entry to a state, which I recently found a need for, and have written a very similar mechanism to achieve the same thing.

What solution would you like?

Here's a snippet of what I produced for my own game:

impl AppExtLifetime for SubApp {
    fn enable_state_entry_despawn<S: States>(&mut self) -> &mut Self {
        self.add_systems(
            StateTransition,
            state_entry_despawn::<S>
                .in_set(TransitionSchedules::<S>::default())
                .run_if(on_event::<StateTransitionEvent<S>>()),
        );
        self
    }
}

What alternative(s) have you considered?

No real alternatives.

Additional context

State transitions are such a powerful and flexible way to orchestrate game entity lifecyles and the flow of the game itself, it would be nice to see more features in this area.

akimakinai commented 1 month ago

IMO having entities "scoped to a particular state" is more simple concept than despawn-on-entry/exit. If StateScoped gets warning (or even instant despawn) against insertion during mismatched state, then these new components could be added to fill the gaps for advanced use.

benfrankel commented 4 days ago

Note that this also opens the door to expanding the type into an enum as such (from pyri_state):

pub enum DespawnOnExit<S: State> {
    Single,
    #[default]
    Recursive,
    Descendants,
    #[doc(hidden)]
    _PhantomData(PhantomData<S>),
}

Also "despawn on enter", "hide on enter", "hide on exit", "disable on enter" (with entity disabling), etc. variants become very reasonable to add.