mirror of
https://github.com/bevyengine/bevy
synced 2024-11-10 07:04:33 +00:00
Simplify state transitions (#13616)
# Objective Prerequisite to #13579. Make state transition schedule running simpler. ## Solution - Remove `should_run_transition` which read the latest event and fake-fire an event for the startup transitions (e.g. startup `OnEnter()`). - Account for startup event, by actually emitting an event when adding states to `App`. - Replace `should_run_transition` with `last_transition`, which is a light wrapper over `EventReader::read().last()`. --------- Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
This commit is contained in:
parent
4b996c75ab
commit
5cb4808026
4 changed files with 50 additions and 52 deletions
|
@ -308,6 +308,11 @@ impl SubApp {
|
|||
.add_event::<StateTransitionEvent<S>>();
|
||||
let schedule = self.get_schedule_mut(StateTransition).unwrap();
|
||||
S::register_state(schedule);
|
||||
let state = self.world.resource::<State<S>>().get().clone();
|
||||
self.world.send_event(StateTransitionEvent {
|
||||
exited: None,
|
||||
entered: Some(state),
|
||||
});
|
||||
}
|
||||
|
||||
self
|
||||
|
@ -318,12 +323,15 @@ impl SubApp {
|
|||
pub fn insert_state<S: FreelyMutableState>(&mut self, state: S) -> &mut Self {
|
||||
if !self.world.contains_resource::<State<S>>() {
|
||||
setup_state_transitions_in_world(&mut self.world, Some(Startup.intern()));
|
||||
self.insert_resource::<State<S>>(State::new(state))
|
||||
self.insert_resource::<State<S>>(State::new(state.clone()))
|
||||
.init_resource::<NextState<S>>()
|
||||
.add_event::<StateTransitionEvent<S>>();
|
||||
|
||||
let schedule = self.get_schedule_mut(StateTransition).unwrap();
|
||||
S::register_state(schedule);
|
||||
self.world.send_event(StateTransitionEvent {
|
||||
exited: None,
|
||||
entered: Some(state),
|
||||
});
|
||||
}
|
||||
|
||||
self
|
||||
|
@ -340,6 +348,11 @@ impl SubApp {
|
|||
self.add_event::<StateTransitionEvent<S>>();
|
||||
let schedule = self.get_schedule_mut(StateTransition).unwrap();
|
||||
S::register_computed_state_systems(schedule);
|
||||
let state = self.world.resource::<State<S>>().get().clone();
|
||||
self.world.send_event(StateTransitionEvent {
|
||||
exited: None,
|
||||
entered: Some(state),
|
||||
});
|
||||
}
|
||||
|
||||
self
|
||||
|
@ -357,6 +370,11 @@ impl SubApp {
|
|||
self.add_event::<StateTransitionEvent<S>>();
|
||||
let schedule = self.get_schedule_mut(StateTransition).unwrap();
|
||||
S::register_sub_state_systems(schedule);
|
||||
let state = self.world.resource::<State<S>>().get().clone();
|
||||
self.world.send_event(StateTransitionEvent {
|
||||
exited: None,
|
||||
entered: Some(state),
|
||||
});
|
||||
}
|
||||
|
||||
self
|
||||
|
|
|
@ -17,17 +17,17 @@ pub trait FreelyMutableState: States {
|
|||
apply_state_transition::<Self>.in_set(ApplyStateTransition::<Self>::apply()),
|
||||
)
|
||||
.add_systems(
|
||||
should_run_transition::<Self, OnEnter<Self>>
|
||||
last_transition::<Self>
|
||||
.pipe(run_enter::<Self>)
|
||||
.in_set(StateTransitionSteps::EnterSchedules),
|
||||
)
|
||||
.add_systems(
|
||||
should_run_transition::<Self, OnExit<Self>>
|
||||
last_transition::<Self>
|
||||
.pipe(run_exit::<Self>)
|
||||
.in_set(StateTransitionSteps::ExitSchedules),
|
||||
)
|
||||
.add_systems(
|
||||
should_run_transition::<Self, OnTransition<Self>>
|
||||
last_transition::<Self>
|
||||
.pipe(run_transition::<Self>)
|
||||
.in_set(StateTransitionSteps::TransitionSchedules),
|
||||
)
|
||||
|
|
|
@ -9,9 +9,8 @@ use self::sealed::StateSetSealed;
|
|||
|
||||
use super::{
|
||||
apply_state_transition, computed_states::ComputedStates, internal_apply_state_transition,
|
||||
run_enter, run_exit, run_transition, should_run_transition, sub_states::SubStates,
|
||||
ApplyStateTransition, OnEnter, OnExit, OnTransition, State, StateTransitionEvent,
|
||||
StateTransitionSteps, States,
|
||||
last_transition, run_enter, run_exit, run_transition, sub_states::SubStates,
|
||||
ApplyStateTransition, State, StateTransitionEvent, StateTransitionSteps, States,
|
||||
};
|
||||
|
||||
mod sealed {
|
||||
|
@ -117,17 +116,17 @@ impl<S: InnerStateSet> StateSet for S {
|
|||
schedule
|
||||
.add_systems(system.in_set(ApplyStateTransition::<T>::apply()))
|
||||
.add_systems(
|
||||
should_run_transition::<T, OnEnter<T>>
|
||||
last_transition::<T>
|
||||
.pipe(run_enter::<T>)
|
||||
.in_set(StateTransitionSteps::EnterSchedules),
|
||||
)
|
||||
.add_systems(
|
||||
should_run_transition::<T, OnExit<T>>
|
||||
last_transition::<T>
|
||||
.pipe(run_exit::<T>)
|
||||
.in_set(StateTransitionSteps::ExitSchedules),
|
||||
)
|
||||
.add_systems(
|
||||
should_run_transition::<T, OnTransition<T>>
|
||||
last_transition::<T>
|
||||
.pipe(run_transition::<T>)
|
||||
.in_set(StateTransitionSteps::TransitionSchedules),
|
||||
)
|
||||
|
@ -181,17 +180,17 @@ impl<S: InnerStateSet> StateSet for S {
|
|||
apply_state_transition::<T>.in_set(StateTransitionSteps::ManualTransitions),
|
||||
)
|
||||
.add_systems(
|
||||
should_run_transition::<T, OnEnter<T>>
|
||||
last_transition::<T>
|
||||
.pipe(run_enter::<T>)
|
||||
.in_set(StateTransitionSteps::EnterSchedules),
|
||||
)
|
||||
.add_systems(
|
||||
should_run_transition::<T, OnExit<T>>
|
||||
last_transition::<T>
|
||||
.pipe(run_exit::<T>)
|
||||
.in_set(StateTransitionSteps::ExitSchedules),
|
||||
)
|
||||
.add_systems(
|
||||
should_run_transition::<T, OnTransition<T>>
|
||||
last_transition::<T>
|
||||
.pipe(run_transition::<T>)
|
||||
.in_set(StateTransitionSteps::TransitionSchedules),
|
||||
)
|
||||
|
@ -232,9 +231,9 @@ macro_rules! impl_state_set_sealed_tuples {
|
|||
|
||||
schedule
|
||||
.add_systems(system.in_set(ApplyStateTransition::<T>::apply()))
|
||||
.add_systems(should_run_transition::<T, OnEnter<T>>.pipe(run_enter::<T>).in_set(StateTransitionSteps::EnterSchedules))
|
||||
.add_systems(should_run_transition::<T, OnExit<T>>.pipe(run_exit::<T>).in_set(StateTransitionSteps::ExitSchedules))
|
||||
.add_systems(should_run_transition::<T, OnTransition<T>>.pipe(run_transition::<T>).in_set(StateTransitionSteps::TransitionSchedules))
|
||||
.add_systems(last_transition::<T>.pipe(run_enter::<T>).in_set(StateTransitionSteps::EnterSchedules))
|
||||
.add_systems(last_transition::<T>.pipe(run_exit::<T>).in_set(StateTransitionSteps::ExitSchedules))
|
||||
.add_systems(last_transition::<T>.pipe(run_transition::<T>).in_set(StateTransitionSteps::TransitionSchedules))
|
||||
.configure_sets(
|
||||
ApplyStateTransition::<T>::apply()
|
||||
.in_set(StateTransitionSteps::DependentTransitions)
|
||||
|
@ -271,9 +270,9 @@ macro_rules! impl_state_set_sealed_tuples {
|
|||
schedule
|
||||
.add_systems(system.in_set(ApplyStateTransition::<T>::apply()))
|
||||
.add_systems(apply_state_transition::<T>.in_set(StateTransitionSteps::ManualTransitions))
|
||||
.add_systems(should_run_transition::<T, OnEnter<T>>.pipe(run_enter::<T>).in_set(StateTransitionSteps::EnterSchedules))
|
||||
.add_systems(should_run_transition::<T, OnExit<T>>.pipe(run_exit::<T>).in_set(StateTransitionSteps::ExitSchedules))
|
||||
.add_systems(should_run_transition::<T, OnTransition<T>>.pipe(run_transition::<T>).in_set(StateTransitionSteps::TransitionSchedules))
|
||||
.add_systems(last_transition::<T>.pipe(run_enter::<T>).in_set(StateTransitionSteps::EnterSchedules))
|
||||
.add_systems(last_transition::<T>.pipe(run_exit::<T>).in_set(StateTransitionSteps::ExitSchedules))
|
||||
.add_systems(last_transition::<T>.pipe(run_transition::<T>).in_set(StateTransitionSteps::TransitionSchedules))
|
||||
.configure_sets(
|
||||
ApplyStateTransition::<T>::apply()
|
||||
.in_set(StateTransitionSteps::DependentTransitions)
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
use std::{marker::PhantomData, mem, ops::DerefMut};
|
||||
use std::{marker::PhantomData, mem};
|
||||
|
||||
use bevy_ecs::{
|
||||
event::{Event, EventReader, EventWriter},
|
||||
schedule::{
|
||||
InternedScheduleLabel, IntoSystemSetConfigs, Schedule, ScheduleLabel, Schedules, SystemSet,
|
||||
},
|
||||
system::{Commands, In, Local, Res, ResMut},
|
||||
system::{Commands, In, ResMut},
|
||||
world::World,
|
||||
};
|
||||
|
||||
|
@ -202,34 +202,18 @@ pub fn apply_state_transition<S: FreelyMutableState>(
|
|||
*next_state_resource.as_mut() = NextState::<S>::Unchanged;
|
||||
}
|
||||
|
||||
pub(crate) fn should_run_transition<S: States, T: ScheduleLabel>(
|
||||
mut first: Local<bool>,
|
||||
res: Option<Res<State<S>>>,
|
||||
mut event: EventReader<StateTransitionEvent<S>>,
|
||||
) -> (Option<StateTransitionEvent<S>>, PhantomData<T>) {
|
||||
let first_mut = first.deref_mut();
|
||||
if !*first_mut {
|
||||
*first_mut = true;
|
||||
if let Some(res) = res {
|
||||
event.clear();
|
||||
|
||||
return (
|
||||
Some(StateTransitionEvent {
|
||||
exited: None,
|
||||
entered: Some(res.get().clone()),
|
||||
}),
|
||||
PhantomData,
|
||||
);
|
||||
}
|
||||
}
|
||||
(event.read().last().cloned(), PhantomData)
|
||||
/// Returns the latest state transition event of type `S`, if any are available.
|
||||
pub fn last_transition<S: States>(
|
||||
mut reader: EventReader<StateTransitionEvent<S>>,
|
||||
) -> Option<StateTransitionEvent<S>> {
|
||||
reader.read().last().cloned()
|
||||
}
|
||||
|
||||
pub(crate) fn run_enter<S: States>(
|
||||
In((transition, _)): In<(Option<StateTransitionEvent<S>>, PhantomData<OnEnter<S>>)>,
|
||||
transition: In<Option<StateTransitionEvent<S>>>,
|
||||
world: &mut World,
|
||||
) {
|
||||
let Some(transition) = transition else {
|
||||
let Some(transition) = transition.0 else {
|
||||
return;
|
||||
};
|
||||
let Some(entered) = transition.entered else {
|
||||
|
@ -240,10 +224,10 @@ pub(crate) fn run_enter<S: States>(
|
|||
}
|
||||
|
||||
pub(crate) fn run_exit<S: States>(
|
||||
In((transition, _)): In<(Option<StateTransitionEvent<S>>, PhantomData<OnExit<S>>)>,
|
||||
transition: In<Option<StateTransitionEvent<S>>>,
|
||||
world: &mut World,
|
||||
) {
|
||||
let Some(transition) = transition else {
|
||||
let Some(transition) = transition.0 else {
|
||||
return;
|
||||
};
|
||||
let Some(exited) = transition.exited else {
|
||||
|
@ -254,13 +238,10 @@ pub(crate) fn run_exit<S: States>(
|
|||
}
|
||||
|
||||
pub(crate) fn run_transition<S: States>(
|
||||
In((transition, _)): In<(
|
||||
Option<StateTransitionEvent<S>>,
|
||||
PhantomData<OnTransition<S>>,
|
||||
)>,
|
||||
transition: In<Option<StateTransitionEvent<S>>>,
|
||||
world: &mut World,
|
||||
) {
|
||||
let Some(transition) = transition else {
|
||||
let Some(transition) = transition.0 else {
|
||||
return;
|
||||
};
|
||||
let Some(exited) = transition.exited else {
|
||||
|
|
Loading…
Reference in a new issue