Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_state/src/state_scoped.rs
6849 views
1
#[cfg(feature = "bevy_reflect")]
2
use bevy_ecs::reflect::ReflectComponent;
3
use bevy_ecs::{
4
component::Component,
5
entity::Entity,
6
message::MessageReader,
7
system::{Commands, Query},
8
};
9
#[cfg(feature = "bevy_reflect")]
10
use bevy_reflect::prelude::*;
11
12
use crate::state::{StateTransitionEvent, States};
13
14
/// Entities marked with this component will be removed
15
/// when the world's state of the matching type no longer matches the supplied value.
16
///
17
/// If you need to disable this behavior, add the attribute `#[states(scoped_entities = false)]` when deriving [`States`].
18
///
19
/// ```
20
/// use bevy_state::prelude::*;
21
/// use bevy_ecs::prelude::*;
22
/// use bevy_ecs::system::ScheduleSystem;
23
///
24
/// #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Default, States)]
25
/// enum GameState {
26
/// #[default]
27
/// MainMenu,
28
/// SettingsMenu,
29
/// InGame,
30
/// }
31
///
32
/// # #[derive(Component)]
33
/// # struct Player;
34
///
35
/// fn spawn_player(mut commands: Commands) {
36
/// commands.spawn((
37
/// DespawnOnExit(GameState::InGame),
38
/// Player
39
/// ));
40
/// }
41
///
42
/// # struct AppMock;
43
/// # impl AppMock {
44
/// # fn init_state<S>(&mut self) {}
45
/// # fn add_systems<S, M>(&mut self, schedule: S, systems: impl IntoScheduleConfigs<ScheduleSystem, M>) {}
46
/// # }
47
/// # struct Update;
48
/// # let mut app = AppMock;
49
///
50
/// app.init_state::<GameState>();
51
/// app.add_systems(OnEnter(GameState::InGame), spawn_player);
52
/// ```
53
#[derive(Component, Clone)]
54
#[cfg_attr(feature = "bevy_reflect", derive(Reflect), reflect(Component, Clone))]
55
pub struct DespawnOnExit<S: States>(pub S);
56
57
impl<S> Default for DespawnOnExit<S>
58
where
59
S: States + Default,
60
{
61
fn default() -> Self {
62
Self(S::default())
63
}
64
}
65
66
/// A deprecated alias for [`DespawnOnExit`].
67
#[deprecated(since = "0.17.0", note = "use DespawnOnExit instead")]
68
pub type StateScoped<S> = DespawnOnExit<S>;
69
70
/// Despawns entities marked with [`DespawnOnExit<S>`] when their state no
71
/// longer matches the world state.
72
pub fn despawn_entities_on_exit_state<S: States>(
73
mut commands: Commands,
74
mut transitions: MessageReader<StateTransitionEvent<S>>,
75
query: Query<(Entity, &DespawnOnExit<S>)>,
76
) {
77
// We use the latest event, because state machine internals generate at most 1
78
// transition event (per type) each frame. No event means no change happened
79
// and we skip iterating all entities.
80
let Some(transition) = transitions.read().last() else {
81
return;
82
};
83
if transition.entered == transition.exited {
84
return;
85
}
86
let Some(exited) = &transition.exited else {
87
return;
88
};
89
for (entity, binding) in &query {
90
if binding.0 == *exited {
91
commands.entity(entity).despawn();
92
}
93
}
94
}
95
96
/// Entities marked with this component will be despawned
97
/// upon entering the given state.
98
///
99
/// ```
100
/// use bevy_state::prelude::*;
101
/// use bevy_ecs::{prelude::*, system::ScheduleSystem};
102
///
103
/// #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Default, States)]
104
/// enum GameState {
105
/// #[default]
106
/// MainMenu,
107
/// SettingsMenu,
108
/// InGame,
109
/// }
110
///
111
/// # #[derive(Component)]
112
/// # struct Player;
113
///
114
/// fn spawn_player(mut commands: Commands) {
115
/// commands.spawn((
116
/// DespawnOnEnter(GameState::MainMenu),
117
/// Player
118
/// ));
119
/// }
120
///
121
/// # struct AppMock;
122
/// # impl AppMock {
123
/// # fn init_state<S>(&mut self) {}
124
/// # fn add_systems<S, M>(&mut self, schedule: S, systems: impl IntoScheduleConfigs<ScheduleSystem, M>) {}
125
/// # }
126
/// # struct Update;
127
/// # let mut app = AppMock;
128
///
129
/// app.init_state::<GameState>();
130
/// app.add_systems(OnEnter(GameState::InGame), spawn_player);
131
/// ```
132
#[derive(Component, Clone)]
133
#[cfg_attr(feature = "bevy_reflect", derive(Reflect), reflect(Component))]
134
pub struct DespawnOnEnter<S: States>(pub S);
135
136
/// Despawns entities marked with [`DespawnOnEnter<S>`] when their state
137
/// matches the world state.
138
pub fn despawn_entities_on_enter_state<S: States>(
139
mut commands: Commands,
140
mut transitions: MessageReader<StateTransitionEvent<S>>,
141
query: Query<(Entity, &DespawnOnEnter<S>)>,
142
) {
143
// We use the latest event, because state machine internals generate at most 1
144
// transition event (per type) each frame. No event means no change happened
145
// and we skip iterating all entities.
146
let Some(transition) = transitions.read().last() else {
147
return;
148
};
149
if transition.entered == transition.exited {
150
return;
151
}
152
let Some(entered) = &transition.entered else {
153
return;
154
};
155
for (entity, binding) in &query {
156
if binding.0 == *entered {
157
commands.entity(entity).despawn();
158
}
159
}
160
}
161
162