pub struct Commands<'w, 's> { /* private fields */ }Expand description
A Command queue to perform structural changes to the World.
Since each command requires exclusive access to the World,
all queued commands are automatically applied in sequence
when the ApplyDeferred system runs (see ApplyDeferred documentation for more details).
Each command can be used to modify the World in arbitrary ways:
- spawning or despawning entities
- inserting components on new or existing entities
- inserting resources
- etc.
For a version of Commands that works in parallel contexts (such as
within Query::par_iter) see
ParallelCommands
§Usage
Add mut commands: Commands as a function argument to your system to get a
copy of this struct that will be applied the next time a copy of ApplyDeferred runs.
Commands are almost always used as a SystemParam.
fn my_system(mut commands: Commands) {
// ...
}§Implementing
Each built-in command is implemented as a separate method, e.g. Commands::spawn.
In addition to the pre-defined command methods, you can add commands with any arbitrary
behavior using Commands::queue, which accepts any type implementing Command.
Since closures and other functions implement this trait automatically, this allows one-shot, anonymous custom commands.
// NOTE: type inference fails here, so annotations are required on the closure.
commands.queue(|w: &mut World| {
// Mutate the world however you want...
});§Error handling
A Command can return a Result,
which will be passed to an error handler if the Result is an error.
The fallback error handler panics. It can be configured via
the FallbackErrorHandler resource.
Alternatively, you can customize the error handler for a specific command
by calling Commands::queue_handled.
The error module provides some simple error handlers for convenience.
Implementations§
Source§impl<'w, 's> Commands<'w, 's>
impl<'w, 's> Commands<'w, 's>
Sourcepub fn new(queue: &'s mut CommandQueue, world: &'w World) -> Commands<'w, 's>
pub fn new(queue: &'s mut CommandQueue, world: &'w World) -> Commands<'w, 's>
Returns a new Commands instance from a CommandQueue and a World.
Sourcepub fn new_from_entities(
queue: &'s mut CommandQueue,
allocator: &'w EntityAllocator,
entities: &'w Entities,
) -> Commands<'w, 's>
pub fn new_from_entities( queue: &'s mut CommandQueue, allocator: &'w EntityAllocator, entities: &'w Entities, ) -> Commands<'w, 's>
Returns a new Commands instance from a CommandQueue and an Entities reference.
Sourcepub fn rebound_to<'q>(&self, queue: &'q mut CommandQueue) -> Commands<'w, 'q>
pub fn rebound_to<'q>(&self, queue: &'q mut CommandQueue) -> Commands<'w, 'q>
Returns a new Commands that writes commands to the provided CommandQueue instead of the one from self.
This is useful if you have a Commands that writes to one queue and you want one that writes to another.
Note that you’re responsible for ensuring the queue eventually writes its commands to the world. One way to
do this is calling Commands::append on a Commands that writes to the world queue. Failure to write a
queue may result in entities being allocated but never spawned, which means those entity IDs are never
freed for reuse.
The original Commands isn’t mutated or borrowed after this returns, so you can keep using it.
Sourcepub fn reborrow(&mut self) -> Commands<'w, '_>
pub fn reborrow(&mut self) -> Commands<'w, '_>
Returns a Commands with a smaller lifetime.
This is useful if you have &mut Commands but need Commands.
§Example
fn my_system(mut commands: Commands) {
// We do our initialization in a separate function,
// which expects an owned `Commands`.
do_initialization(commands.reborrow());
// Since we only reborrowed the commands instead of moving them, we can still use them.
commands.spawn_empty();
}Sourcepub fn append(&mut self, other: &mut CommandQueue)
pub fn append(&mut self, other: &mut CommandQueue)
Take all commands from other and append them to self, leaving other empty.
Examples found in repository?
128fn handle_tasks(
129 mut commands: Commands,
130 mut transform_tasks: Query<(Entity, &mut ComputeTransform)>,
131) {
132 for (entity, mut task) in &mut transform_tasks {
133 // Use `check_ready` to efficiently poll the task without blocking the main thread.
134 if let Some(mut commands_queue) = check_ready(&mut task.0) {
135 // Append the returned command queue to execute it later.
136 commands.append(&mut commands_queue);
137 // Task is complete, so remove the task component from the entity.
138 commands.entity(entity).remove::<ComputeTransform>();
139 }
140 }
141}Sourcepub fn spawn_empty(&mut self) -> EntityCommands<'_>
pub fn spawn_empty(&mut self) -> EntityCommands<'_>
Spawns a new empty Entity and returns its corresponding EntityCommands.
§Example
#[derive(Component)]
struct Label(&'static str);
#[derive(Component)]
struct Strength(u32);
#[derive(Component)]
struct Agility(u32);
fn example_system(mut commands: Commands) {
// Create a new empty entity.
commands.spawn_empty();
// Create another empty entity.
commands.spawn_empty()
// Add a new component bundle to the entity.
.insert((Strength(1), Agility(2)))
// Add a single component to the entity.
.insert(Label("hello world"));
}§See also
spawnto spawn an entity with components.spawn_batchto spawn many entities with the same combination of components.
Examples found in repository?
66fn spawn_tasks(mut commands: Commands) {
67 let thread_pool = AsyncComputeTaskPool::get();
68 for x in 0..NUM_CUBES {
69 for y in 0..NUM_CUBES {
70 for z in 0..NUM_CUBES {
71 // Spawn new task on the AsyncComputeTaskPool; the task will be
72 // executed in the background, and the Task future returned by
73 // spawn() can be used to poll for the result
74 let entity = commands.spawn_empty().id();
75 let task = thread_pool.spawn(async move {
76 let duration = Duration::from_secs_f32(rand::rng().random_range(0.05..5.0));
77
78 // Pretend this is a time-intensive function. :)
79 Delay::new(duration).await;
80
81 // Such hard work, all done!
82 let transform = Transform::from_xyz(x as f32, y as f32, z as f32);
83 let mut command_queue = CommandQueue::default();
84
85 // we use a raw command queue to pass a FnOnce(&mut World) back to be
86 // applied in a deferred manner.
87 command_queue.push(move |world: &mut World| {
88 let (box_mesh_handle, box_material_handle) = {
89 let mut system_state = SystemState::<(
90 Res<BoxMeshHandle>,
91 Res<BoxMaterialHandle>,
92 )>::new(world);
93 let (box_mesh_handle, box_material_handle) =
94 system_state.get_mut(world).unwrap();
95
96 (box_mesh_handle.clone(), box_material_handle.clone())
97 };
98
99 world
100 .entity_mut(entity)
101 // Add our new `Mesh3d` and `MeshMaterial3d` to our tagged entity
102 .insert((
103 Mesh3d(box_mesh_handle),
104 MeshMaterial3d(box_material_handle),
105 transform,
106 ));
107 });
108
109 command_queue
110 });
111
112 // Add our new task as a component
113 commands.entity(entity).insert(ComputeTransform(task));
114 }
115 }
116 }
117}More examples
354fn spawn_tree(
355 parent_map: &[usize],
356 commands: &mut Commands,
357 update_filter: &UpdateFilter,
358 root_transform: Transform,
359) -> InsertResult {
360 // total count (# of nodes + root)
361 let count = parent_map.len() + 1;
362
363 #[derive(Default, Clone, Copy)]
364 struct NodeInfo {
365 child_count: u32,
366 depth: u32,
367 }
368
369 // node index -> entity lookup list
370 let mut ents: Vec<Entity> = Vec::with_capacity(count);
371 let mut node_info: Vec<NodeInfo> = vec![default(); count];
372 for (i, &parent_idx) in parent_map.iter().enumerate() {
373 // assert spawn order (parent must be processed before child)
374 assert!(parent_idx <= i, "invalid spawn order");
375 node_info[parent_idx].child_count += 1;
376 }
377
378 // insert root
379 ents.push(commands.spawn(root_transform).id());
380
381 let mut result = InsertResult::default();
382 let mut rng = rand::rng();
383 // used to count through the number of children (used only for visual layout)
384 let mut child_idx: Vec<u16> = vec![0; count];
385
386 // insert children
387 for (current_idx, &parent_idx) in parent_map.iter().enumerate() {
388 let current_idx = current_idx + 1;
389
390 // separation factor to visually separate children (0..1)
391 let sep = child_idx[parent_idx] as f32 / node_info[parent_idx].child_count as f32;
392 child_idx[parent_idx] += 1;
393
394 // calculate and set depth
395 // this works because it's guaranteed that we have already iterated over the parent
396 let depth = node_info[parent_idx].depth + 1;
397 let info = &mut node_info[current_idx];
398 info.depth = depth;
399
400 // update max depth of tree
401 result.maximum_depth = result.maximum_depth.max(depth.try_into().unwrap());
402
403 // insert child
404 let child_entity = {
405 let mut cmd = commands.spawn_empty();
406
407 // check whether or not to update this node
408 let update = (rng.random::<f32>() <= update_filter.probability)
409 && (depth >= update_filter.min_depth && depth <= update_filter.max_depth);
410
411 if update {
412 cmd.insert(UpdateValue(sep));
413 result.active_nodes += 1;
414 }
415
416 let transform = {
417 let mut translation = Vec3::ZERO;
418 // use the same placement fn as the `update` system
419 // this way the entities won't be all at (0, 0, 0) when they don't have an `Update` component
420 set_translation(&mut translation, sep);
421 Transform::from_translation(translation)
422 };
423
424 // only insert the components necessary for the transform propagation
425 cmd.insert(transform);
426
427 cmd.id()
428 };
429
430 commands.entity(ents[parent_idx]).add_child(child_entity);
431
432 ents.push(child_entity);
433 }
434
435 result.inserted_nodes = ents.len();
436 result
437}Sourcepub fn spawn<T>(&mut self, bundle: T) -> EntityCommands<'_>where
T: Bundle,
pub fn spawn<T>(&mut self, bundle: T) -> EntityCommands<'_>where
T: Bundle,
Spawns a new Entity with the given components
and returns the entity’s corresponding EntityCommands.
To spawn many entities with the same combination of components,
spawn_batch can be used for better performance.
§Example
#[derive(Component)]
struct ComponentA(u32);
#[derive(Component)]
struct ComponentB(u32);
#[derive(Bundle)]
struct ExampleBundle {
a: ComponentA,
b: ComponentB,
}
fn example_system(mut commands: Commands) {
// Create a new entity with a single component.
commands.spawn(ComponentA(1));
// Create a new entity with two components using a "tuple bundle".
commands.spawn((ComponentA(2), ComponentB(1)));
// Create a new entity with a component bundle.
commands.spawn(ExampleBundle {
a: ComponentA(3),
b: ComponentB(2),
});
}§See also
spawn_emptyto spawn an entity without any components.spawn_batchto spawn many entities with the same combination of components.
Examples found in repository?
62fn setup(mut commands: Commands) {
63 commands.spawn(Camera2d);
64}
65
66#[derive(Resource)]
67struct Delta(Duration);
68
69fn setup_common(
70 commands: &mut Commands,
71 time: &Res<Time>,
72 delta: &mut ResMut<Delta>,
73 title: &str,
74 stage: Showcase,
75) {
76 delta.0 = time.elapsed();
77 commands.spawn((
78 Text::new(title),
79 TextFont::from_font_size(36.),
80 DespawnOnExit(stage),
81 ));
82}
83
84fn setup_with_children(
85 mut commands: Commands,
86 asset_server: Res<AssetServer>,
87 time: Res<Time>,
88 mut delta: ResMut<Delta>,
89) {
90 let texture = asset_server.load("branding/icon.png");
91
92 setup_common(
93 &mut commands,
94 &time,
95 &mut delta,
96 "with_children()\nPress Space to continue",
97 Showcase::WithChildren,
98 );
99
100 // Spawn a root entity with no parent
101 let parent = commands
102 .spawn((
103 Sprite::from_image(texture.clone()),
104 Transform::from_scale(Vec3::splat(0.75)),
105 DespawnOnExit(Showcase::WithChildren),
106 ))
107 // With that entity as a parent, run a lambda that spawns its children
108 .with_children(|parent| {
109 // parent is a ChildSpawnerCommands, which has a similar API to Commands
110 parent.spawn((
111 Transform::from_xyz(250.0, 0.0, 0.0).with_scale(Vec3::splat(0.75)),
112 Sprite {
113 image: texture.clone(),
114 color: BLUE.into(),
115 ..default()
116 },
117 ));
118 })
119 // Store parent entity for next sections
120 .id();
121
122 // Another way is to use the add_child function to add children after the parent
123 // entity has already been spawned.
124 let child = commands
125 .spawn((
126 Sprite {
127 image: texture.clone(),
128 color: LIME.into(),
129 ..default()
130 },
131 Transform::from_xyz(0.0, 250.0, 0.0).with_scale(Vec3::splat(0.75)),
132 ))
133 .id();
134
135 // Add child to the parent.
136 commands.entity(parent).add_child(child);
137}
138
139fn setup_children_spawn(
140 mut commands: Commands,
141 asset_server: Res<AssetServer>,
142 time: Res<Time>,
143 mut delta: ResMut<Delta>,
144) {
145 let texture = asset_server.load("branding/icon.png");
146
147 setup_common(
148 &mut commands,
149 &time,
150 &mut delta,
151 "Children::spawn() \nPress Space to continue",
152 Showcase::ChildrenSpawn,
153 );
154
155 // Children can also be spawned using the `Children` component as part of the parent's bundle.
156 commands.spawn((
157 Sprite::from_image(texture.clone()),
158 Transform::from_scale(Vec3::splat(0.75)),
159 DespawnOnExit(Showcase::ChildrenSpawn),
160 Children::spawn((
161 Spawn((
162 Transform::from_xyz(250.0, 0.0, 0.0).with_scale(Vec3::splat(0.75)),
163 Sprite {
164 image: texture.clone(),
165 color: BLUE.into(),
166 ..default()
167 },
168 )),
169 // since they have to be explicitly created, `Children::spawn` can
170 // mix implementers of `SpawnableList` while `children!` cannot.
171 SpawnWith(|spawner: &mut RelatedSpawner<'_, ChildOf>| {
172 spawner.spawn((
173 Transform::from_xyz(0.0, 250.0, 0.0).with_scale(Vec3::splat(0.75)),
174 Sprite {
175 image: texture,
176 color: LIME.into(),
177 ..default()
178 },
179 ));
180 }),
181 )),
182 ));
183}
184
185fn spawn_children_macro(
186 mut commands: Commands,
187 asset_server: Res<AssetServer>,
188 time: Res<Time>,
189 mut delta: ResMut<Delta>,
190) {
191 let texture = asset_server.load("branding/icon.png");
192
193 setup_common(
194 &mut commands,
195 &time,
196 &mut delta,
197 "children!() \nPress Space to continue",
198 Showcase::ChildrenMacro,
199 );
200
201 // The `children!` macro provides a convenient way to define children inline with their parent.
202 commands.spawn((
203 Sprite::from_image(texture.clone()),
204 Transform::from_scale(Vec3::splat(0.75)),
205 DespawnOnExit(Showcase::ChildrenMacro),
206 children![
207 (
208 Transform::from_xyz(250.0, 0.0, 0.0).with_scale(Vec3::splat(0.75)),
209 Sprite {
210 image: texture.clone(),
211 color: BLUE.into(),
212 ..default()
213 },
214 ),
215 (
216 Transform::from_xyz(0.0, 250.0, 0.0).with_scale(Vec3::splat(0.75)),
217 Sprite {
218 image: texture,
219 color: LIME.into(),
220 ..default()
221 },
222 )
223 ],
224 ));
225}
226
227fn setup_children_iter(
228 mut commands: Commands,
229 asset_server: Res<AssetServer>,
230 time: Res<Time>,
231 mut delta: ResMut<Delta>,
232) {
233 let texture = asset_server.load("branding/icon.png");
234
235 setup_common(
236 &mut commands,
237 &time,
238 &mut delta,
239 "SpawnIter() \nPress Space to continue",
240 Showcase::ChildrenIter,
241 );
242
243 // You can also spawn children from an iterator yielding bundles.
244 let child_components = [
245 (
246 Transform::from_xyz(250.0, 0.0, 0.0).with_scale(Vec3::splat(0.75)),
247 BLUE,
248 ),
249 (
250 Transform::from_xyz(0.0, 250.0, 0.0).with_scale(Vec3::splat(0.75)),
251 LIME,
252 ),
253 ];
254
255 commands.spawn((
256 Sprite::from_image(texture.clone()),
257 Transform::from_scale(Vec3::splat(0.75)),
258 DespawnOnExit(Showcase::ChildrenIter),
259 Children::spawn(SpawnIter(child_components.into_iter().map(
260 move |(transform, color)| {
261 (
262 transform,
263 Sprite {
264 image: texture.clone(),
265 color: color.into(),
266 ..default()
267 },
268 )
269 },
270 ))),
271 ));
272}
273
274fn setup_children_related(
275 mut commands: Commands,
276 asset_server: Res<AssetServer>,
277 time: Res<Time>,
278 mut delta: ResMut<Delta>,
279) {
280 let texture = asset_server.load("branding/icon.png");
281
282 setup_common(
283 &mut commands,
284 &time,
285 &mut delta,
286 "related!() \nPress Space to continue",
287 Showcase::Related,
288 );
289
290 // You can also spawn entities with relationships other than parent/child.
291 commands.spawn((
292 Sprite::from_image(texture.clone()),
293 Transform::from_scale(Vec3::splat(0.75)),
294 DespawnOnExit(Showcase::Related),
295 // the `related!` macro will spawn entities according to the `Children: RelationshipTarget` trait, but other types implementing `RelationshipTarget` can be used as well.
296 related!(Children[
297 (
298 Transform::from_xyz(250.0, 0.0, 0.0).with_scale(Vec3::splat(0.75)),
299 Sprite {
300 image: texture.clone(),
301 color: BLUE.into(),
302 ..default()
303 },
304 ),
305 (
306 Transform::from_xyz(0.0, 250.0, 0.0).with_scale(Vec3::splat(0.75)),
307 Sprite {
308 image: texture,
309 color: LIME.into(),
310 ..default()
311 },
312 )
313 ]),
314 ));
315}More examples
47fn setup(mut commands: Commands) {
48 commands.spawn(Camera2d);
49}
50
51mod splash {
52 use bevy::prelude::*;
53
54 use super::GameState;
55
56 // This plugin will display a splash screen with Bevy logo for 1 second before switching to the menu
57 pub fn splash_plugin(app: &mut App) {
58 // As this plugin is managing the splash screen, it will focus on the state `GameState::Splash`
59 app
60 // When entering the state, spawn everything needed for this screen
61 .add_systems(OnEnter(GameState::Splash), splash_setup)
62 // While in this state, run the `countdown` system
63 .add_systems(Update, countdown.run_if(in_state(GameState::Splash)));
64 }
65
66 // Tag component used to tag entities added on the splash screen
67 #[derive(Component)]
68 struct OnSplashScreen;
69
70 // Newtype to use a `Timer` for this screen as a resource
71 #[derive(Resource, Deref, DerefMut)]
72 struct SplashTimer(Timer);
73
74 fn splash_setup(mut commands: Commands, asset_server: Res<AssetServer>) {
75 let icon = asset_server.load("branding/icon.png");
76 // Display the logo
77 commands.spawn((
78 // This entity will be despawned when exiting the state
79 DespawnOnExit(GameState::Splash),
80 Node {
81 align_items: AlignItems::Center,
82 justify_content: JustifyContent::Center,
83 width: percent(100),
84 height: percent(100),
85 ..default()
86 },
87 OnSplashScreen,
88 children![(
89 ImageNode::new(icon),
90 Node {
91 // This will set the logo to be 200px wide, and auto adjust its height
92 width: px(200),
93 ..default()
94 },
95 )],
96 ));
97 // Insert the timer as a resource
98 commands.insert_resource(SplashTimer(Timer::from_seconds(1.0, TimerMode::Once)));
99 }
100
101 // Tick the timer, and change state when finished
102 fn countdown(
103 mut game_state: ResMut<NextState<GameState>>,
104 time: Res<Time>,
105 mut timer: ResMut<SplashTimer>,
106 ) {
107 if timer.tick(time.delta()).is_finished() {
108 game_state.set(GameState::Menu);
109 }
110 }
111}
112
113mod game {
114 use bevy::{
115 color::palettes::basic::{BLUE, LIME},
116 prelude::*,
117 };
118
119 use super::{DisplayQuality, GameState, Volume, TEXT_COLOR};
120
121 // This plugin will contain the game. In this case, it's just be a screen that will
122 // display the current settings for 5 seconds before returning to the menu
123 pub fn game_plugin(app: &mut App) {
124 app.add_systems(OnEnter(GameState::Game), game_setup)
125 .add_systems(Update, game.run_if(in_state(GameState::Game)));
126 }
127
128 // Tag component used to tag entities added on the game screen
129 #[derive(Component)]
130 struct OnGameScreen;
131
132 #[derive(Resource, Deref, DerefMut)]
133 struct GameTimer(Timer);
134
135 fn game_setup(
136 mut commands: Commands,
137 display_quality: Res<DisplayQuality>,
138 volume: Res<Volume>,
139 ) {
140 commands.spawn((
141 DespawnOnExit(GameState::Game),
142 Node {
143 width: percent(100),
144 height: percent(100),
145 // center children
146 align_items: AlignItems::Center,
147 justify_content: JustifyContent::Center,
148 ..default()
149 },
150 OnGameScreen,
151 children![(
152 Node {
153 // This will display its children in a column, from top to bottom
154 flex_direction: FlexDirection::Column,
155 // `align_items` will align children on the cross axis. Here the main axis is
156 // vertical (column), so the cross axis is horizontal. This will center the
157 // children
158 align_items: AlignItems::Center,
159 ..default()
160 },
161 BackgroundColor(Color::BLACK),
162 children![
163 (
164 Text::new("Will be back to the menu shortly..."),
165 TextFont {
166 font_size: FontSize::Px(67.0),
167 ..default()
168 },
169 TextColor(TEXT_COLOR),
170 Node {
171 margin: UiRect::all(px(50)),
172 ..default()
173 },
174 ),
175 (
176 Text::default(),
177 Node {
178 margin: UiRect::all(px(50)),
179 ..default()
180 },
181 children![
182 (
183 TextSpan(format!("quality: {:?}", *display_quality)),
184 TextFont {
185 font_size: FontSize::Px(50.0),
186 ..default()
187 },
188 TextColor(BLUE.into()),
189 ),
190 (
191 TextSpan::new(" - "),
192 TextFont {
193 font_size: FontSize::Px(50.0),
194 ..default()
195 },
196 TextColor(TEXT_COLOR),
197 ),
198 (
199 TextSpan(format!("volume: {:?}", *volume)),
200 TextFont {
201 font_size: FontSize::Px(50.0),
202 ..default()
203 },
204 TextColor(LIME.into()),
205 ),
206 ]
207 ),
208 ]
209 )],
210 ));
211 // Spawn a 5 seconds timer to trigger going back to the menu
212 commands.insert_resource(GameTimer(Timer::from_seconds(5.0, TimerMode::Once)));
213 }
214
215 // Tick the timer, and change state when finished
216 fn game(
217 time: Res<Time>,
218 mut game_state: ResMut<NextState<GameState>>,
219 mut timer: ResMut<GameTimer>,
220 ) {
221 if timer.tick(time.delta()).is_finished() {
222 game_state.set(GameState::Menu);
223 }
224 }
225}
226
227mod menu {
228 use bevy::{
229 app::AppExit,
230 color::palettes::css::CRIMSON,
231 ecs::component::Mutable,
232 ecs::spawn::{SpawnIter, SpawnWith},
233 picking::prelude::*,
234 prelude::*,
235 ui::Checked,
236 ui_widgets::{Activate, ActivateOnPress, Button, RadioButton, RadioGroup, ValueChange},
237 };
238
239 use super::{DisplayQuality, GameState, Setting, Volume, TEXT_COLOR};
240
241 // This plugin manages the menu, with 5 different screens:
242 // - a main menu with "New Game", "Settings", "Quit"
243 // - a settings menu with two submenus and a back button
244 // - two settings screen with a setting that can be set and a back button
245 pub fn menu_plugin(app: &mut App) {
246 app
247 // At start, the menu is not enabled. This will be changed in `menu_setup` when
248 // entering the `GameState::Menu` state.
249 // Current screen in the menu is handled by an independent state from `GameState`
250 .init_state::<MenuState>()
251 .add_systems(OnEnter(GameState::Menu), menu_setup)
252 // Systems to handle the main menu screen
253 .add_systems(OnEnter(MenuState::Main), main_menu_setup)
254 // Systems to handle the settings menu screen
255 .add_systems(OnEnter(MenuState::Settings), settings_menu_setup)
256 // Systems to handle the display settings screen
257 .add_systems(
258 OnEnter(MenuState::SettingsDisplay),
259 display_settings_menu_setup,
260 )
261 .add_observer(
262 on_value_change_setting_radio::<DisplayQuality>
263 .run_if(in_state(MenuState::SettingsDisplay)),
264 )
265 // Systems to handle the sound settings screen
266 .add_systems(OnEnter(MenuState::SettingsSound), sound_settings_menu_setup)
267 .add_observer(
268 on_value_change_setting_radio::<Volume>.run_if(in_state(MenuState::SettingsSound)),
269 )
270 // Observer that handles navigation within the app upon pressing certain buttons.
271 .add_observer(on_button_activate_update_states)
272 // Observers for button styling (regular buttons and radio buttons)
273 .add_observer(on_button_over_style)
274 .add_observer(on_button_out_style)
275 .add_observer(on_radio_button_press_style)
276 .add_observer(on_radio_button_release_style);
277 }
278
279 // State used for the current menu screen
280 #[derive(Clone, Copy, Default, Eq, PartialEq, Debug, Hash, States)]
281 enum MenuState {
282 Main,
283 Settings,
284 SettingsDisplay,
285 SettingsSound,
286 #[default]
287 Disabled,
288 }
289
290 // Tag component used to tag entities added on the main menu screen
291 #[derive(Component)]
292 struct OnMainMenuScreen;
293
294 // Tag component used to tag entities added on the settings menu screen
295 #[derive(Component)]
296 struct OnSettingsMenuScreen;
297
298 // Tag component used to tag entities added on the display settings menu screen
299 #[derive(Component)]
300 struct OnDisplaySettingsMenuScreen;
301
302 // Tag component used to tag entities added on the sound settings menu screen
303 #[derive(Component)]
304 struct OnSoundSettingsMenuScreen;
305
306 const NORMAL_BUTTON: Color = Color::srgb(0.15, 0.15, 0.15);
307 const HOVERED_BUTTON: Color = Color::srgb(0.25, 0.25, 0.25);
308 const HOVERED_PRESSED_BUTTON: Color = Color::srgb(0.25, 0.65, 0.25);
309 const PRESSED_BUTTON: Color = Color::srgb(0.35, 0.75, 0.35);
310
311 // All actions that can be triggered from a button click
312 #[derive(Component)]
313 enum MenuButtonAction {
314 Play,
315 Settings,
316 SettingsDisplay,
317 SettingsSound,
318 BackToMainMenu,
319 BackToSettings,
320 Quit,
321 }
322
323 /// Observer that changes the background color to hovered over buttons / radio buttons to the correct color.
324 fn on_button_over_style(
325 event: On<PointerOver>,
326 mut button_q: Query<&mut BackgroundColor, (With<Button>, Without<RadioButton>)>,
327 mut radio_button_q: Query<
328 (&mut BackgroundColor, Has<Checked>),
329 (With<RadioButton>, Without<Button>),
330 >,
331 ) {
332 if let Ok(mut background_color) = button_q.get_mut(event.entity) {
333 *background_color = HOVERED_BUTTON.into();
334 }
335 if let Ok((mut background_color, is_checked)) = radio_button_q.get_mut(event.entity) {
336 if is_checked {
337 *background_color = HOVERED_PRESSED_BUTTON.into();
338 } else {
339 *background_color = HOVERED_BUTTON.into();
340 }
341 }
342 }
343
344 /// Observer that returns the normal background color to buttons / radio buttons that are hovered out of.
345 fn on_button_out_style(
346 event: On<PointerOut>,
347 mut bg_q: Query<&mut BackgroundColor, (With<Button>, Without<RadioButton>)>,
348 mut radio_button_q: Query<
349 (&mut BackgroundColor, Has<Checked>),
350 (With<RadioButton>, Without<Button>),
351 >,
352 ) {
353 if let Ok(mut background_color) = bg_q.get_mut(event.entity) {
354 *background_color = NORMAL_BUTTON.into();
355 }
356 if let Ok((mut background_color, is_checked)) = radio_button_q.get_mut(event.entity) {
357 if is_checked {
358 *background_color = PRESSED_BUTTON.into();
359 } else {
360 *background_color = NORMAL_BUTTON.into();
361 }
362 }
363 }
364
365 /// Observer that changes the background color of radio buttons that are pressed
366 fn on_radio_button_press_style(
367 event: On<PointerPress>,
368 mut radio_button_q: Query<&mut BackgroundColor, With<RadioButton>>,
369 ) {
370 if let Ok(mut background_color) = radio_button_q.get_mut(event.entity) {
371 *background_color = PRESSED_BUTTON.into();
372 }
373 }
374
375 /// Observer that changes the background color of radio buttons that are released
376 fn on_radio_button_release_style(
377 event: On<PointerRelease>,
378 mut radio_button_q: Query<(&mut BackgroundColor, Has<Checked>), With<RadioButton>>,
379 ) {
380 if let Ok((mut background_color, is_checked)) = radio_button_q.get_mut(event.entity) {
381 if is_checked {
382 *background_color = HOVERED_PRESSED_BUTTON.into();
383 } else {
384 *background_color = HOVERED_BUTTON.into();
385 }
386 }
387 }
388
389 // This system updates the settings when a new value for a setting is selected, and marks
390 // the radio button as the one currently selected
391 fn on_value_change_setting_radio<
392 T: Resource<Mutability = Mutable> + Component + PartialEq + Copy,
393 >(
394 event: On<ValueChange<Entity>>,
395 new_setting_query: Query<(&Setting<T>, Entity), (With<RadioButton>, Without<Checked>)>,
396 previous_query: Single<(Entity, &mut BackgroundColor), (With<RadioButton>, With<Checked>)>,
397 mut commands: Commands,
398 mut setting: ResMut<T>,
399 ) {
400 if let Ok((radio_setting, entity)) = new_setting_query.get(event.value)
401 && *setting != radio_setting.0
402 {
403 let (previous, mut previous_button_color) = previous_query.into_inner();
404 *previous_button_color = NORMAL_BUTTON.into();
405 commands.entity(previous).remove::<Checked>();
406 commands.entity(entity).insert(Checked);
407 *setting = radio_setting.0;
408 }
409 }
410
411 fn menu_setup(mut menu_state: ResMut<NextState<MenuState>>) {
412 menu_state.set(MenuState::Main);
413 }
414
415 fn main_menu_setup(mut commands: Commands, asset_server: Res<AssetServer>) {
416 // Common style for all buttons on the screen
417 let button_node = Node {
418 width: px(300),
419 height: px(65),
420 margin: UiRect::all(px(20)),
421 justify_content: JustifyContent::Center,
422 align_items: AlignItems::Center,
423 ..default()
424 };
425 let button_icon_node = Node {
426 width: px(30),
427 // This takes the icons out of the flexbox flow, to be positioned exactly
428 position_type: PositionType::Absolute,
429 // The icon will be close to the left border of the button
430 left: px(10),
431 ..default()
432 };
433 let button_text_font = TextFont {
434 font_size: FontSize::Px(33.0),
435 ..default()
436 };
437
438 let right_icon = asset_server.load("textures/Game Icons/right.png");
439 let wrench_icon = asset_server.load("textures/Game Icons/wrench.png");
440 let exit_icon = asset_server.load("textures/Game Icons/exitRight.png");
441
442 commands.spawn((
443 DespawnOnExit(MenuState::Main),
444 Node {
445 width: percent(100),
446 height: percent(100),
447 align_items: AlignItems::Center,
448 justify_content: JustifyContent::Center,
449 ..default()
450 },
451 OnMainMenuScreen,
452 children![(
453 Node {
454 flex_direction: FlexDirection::Column,
455 align_items: AlignItems::Center,
456 ..default()
457 },
458 BackgroundColor(CRIMSON.into()),
459 children![
460 // Display the game name
461 (
462 Text::new("Bevy Game Menu UI"),
463 TextFont {
464 font_size: FontSize::Px(67.0),
465 ..default()
466 },
467 TextColor(TEXT_COLOR),
468 Node {
469 margin: UiRect::all(px(50)),
470 ..default()
471 },
472 ),
473 // Display three buttons for each action available from the main menu:
474 // - new game
475 // - settings
476 // - quit
477 (
478 Button,
479 ActivateOnPress,
480 button_node.clone(),
481 BackgroundColor(NORMAL_BUTTON),
482 MenuButtonAction::Play,
483 children![
484 (ImageNode::new(right_icon), button_icon_node.clone()),
485 (
486 Text::new("New Game"),
487 button_text_font.clone(),
488 TextColor(TEXT_COLOR),
489 ),
490 ]
491 ),
492 (
493 Button,
494 ActivateOnPress,
495 button_node.clone(),
496 BackgroundColor(NORMAL_BUTTON),
497 MenuButtonAction::Settings,
498 children![
499 (ImageNode::new(wrench_icon), button_icon_node.clone()),
500 (
501 Text::new("Settings"),
502 button_text_font.clone(),
503 TextColor(TEXT_COLOR),
504 ),
505 ]
506 ),
507 (
508 Button,
509 ActivateOnPress,
510 button_node,
511 BackgroundColor(NORMAL_BUTTON),
512 MenuButtonAction::Quit,
513 children![
514 (ImageNode::new(exit_icon), button_icon_node),
515 (Text::new("Quit"), button_text_font, TextColor(TEXT_COLOR),),
516 ]
517 ),
518 ]
519 )],
520 ));
521 }
522
523 fn settings_menu_setup(mut commands: Commands) {
524 let button_node = Node {
525 width: px(200),
526 height: px(65),
527 margin: UiRect::all(px(20)),
528 justify_content: JustifyContent::Center,
529 align_items: AlignItems::Center,
530 ..default()
531 };
532
533 let button_text_style = (
534 TextFont {
535 font_size: FontSize::Px(33.0),
536 ..default()
537 },
538 TextColor(TEXT_COLOR),
539 );
540
541 commands.spawn((
542 DespawnOnExit(MenuState::Settings),
543 Node {
544 width: percent(100),
545 height: percent(100),
546 align_items: AlignItems::Center,
547 justify_content: JustifyContent::Center,
548 ..default()
549 },
550 OnSettingsMenuScreen,
551 children![(
552 Node {
553 flex_direction: FlexDirection::Column,
554 align_items: AlignItems::Center,
555 ..default()
556 },
557 BackgroundColor(CRIMSON.into()),
558 Children::spawn(SpawnIter(
559 [
560 (MenuButtonAction::SettingsDisplay, "Display"),
561 (MenuButtonAction::SettingsSound, "Sound"),
562 (MenuButtonAction::BackToMainMenu, "Back"),
563 ]
564 .into_iter()
565 .map(move |(action, text)| {
566 (
567 Button,
568 ActivateOnPress,
569 button_node.clone(),
570 BackgroundColor(NORMAL_BUTTON),
571 action,
572 children![(Text::new(text), button_text_style.clone())],
573 )
574 })
575 ))
576 )],
577 ));
578 }
579
580 fn display_settings_menu_setup(mut commands: Commands, display_quality: Res<DisplayQuality>) {
581 fn button_node() -> Node {
582 Node {
583 width: px(200),
584 height: px(65),
585 margin: UiRect::all(px(20)),
586 justify_content: JustifyContent::Center,
587 align_items: AlignItems::Center,
588 ..default()
589 }
590 }
591 fn button_text_style() -> impl Bundle {
592 (
593 TextFont {
594 font_size: FontSize::Px(33.0),
595 ..default()
596 },
597 TextColor(TEXT_COLOR),
598 )
599 }
600
601 let display_quality = *display_quality;
602 commands.spawn((
603 DespawnOnExit(MenuState::SettingsDisplay),
604 Node {
605 width: percent(100),
606 height: percent(100),
607 align_items: AlignItems::Center,
608 justify_content: JustifyContent::Center,
609 ..default()
610 },
611 OnDisplaySettingsMenuScreen,
612 children![(
613 Node {
614 flex_direction: FlexDirection::Column,
615 align_items: AlignItems::Center,
616 ..default()
617 },
618 BackgroundColor(CRIMSON.into()),
619 children![
620 // Create a new `Node`, this time not setting its `flex_direction`. It will
621 // use the default value, `FlexDirection::Row`, from left to right.
622 // Because the setting can only be one of three values, a RadioGroup
623 // is used, with each individual value as a RadioButton
624 (
625 RadioGroup,
626 Node {
627 align_items: AlignItems::Center,
628 ..default()
629 },
630 BackgroundColor(CRIMSON.into()),
631 Children::spawn((
632 // Display a label for the current setting
633 Spawn((Text::new("Display Quality"), button_text_style())),
634 SpawnWith(move |parent: &mut ChildSpawner| {
635 for quality_setting in [
636 DisplayQuality::Low,
637 DisplayQuality::Medium,
638 DisplayQuality::High,
639 ] {
640 let mut entity = parent.spawn((
641 RadioButton,
642 Node {
643 width: px(150),
644 height: px(65),
645 ..button_node()
646 },
647 BackgroundColor(NORMAL_BUTTON),
648 Setting(quality_setting),
649 children![(
650 Text::new(format!("{quality_setting:?}")),
651 button_text_style(),
652 )],
653 ));
654 if display_quality == quality_setting {
655 entity.insert((Checked, BackgroundColor(PRESSED_BUTTON)));
656 }
657 }
658 })
659 ))
660 ),
661 // Display the back button to return to the settings screen
662 (
663 Button,
664 ActivateOnPress,
665 button_node(),
666 BackgroundColor(NORMAL_BUTTON),
667 MenuButtonAction::BackToSettings,
668 children![(Text::new("Back"), button_text_style())]
669 )
670 ]
671 )],
672 ));
673 }
674
675 fn sound_settings_menu_setup(mut commands: Commands, volume: Res<Volume>) {
676 let button_node = Node {
677 width: px(200),
678 height: px(65),
679 margin: UiRect::all(px(20)),
680 justify_content: JustifyContent::Center,
681 align_items: AlignItems::Center,
682 ..default()
683 };
684 let button_text_style = (
685 TextFont {
686 font_size: FontSize::Px(33.0),
687 ..default()
688 },
689 TextColor(TEXT_COLOR),
690 );
691
692 let volume = *volume;
693 let button_node_clone = button_node.clone();
694 commands.spawn((
695 DespawnOnExit(MenuState::SettingsSound),
696 Node {
697 width: percent(100),
698 height: percent(100),
699 align_items: AlignItems::Center,
700 justify_content: JustifyContent::Center,
701 ..default()
702 },
703 OnSoundSettingsMenuScreen,
704 children![(
705 Node {
706 flex_direction: FlexDirection::Column,
707 align_items: AlignItems::Center,
708 ..default()
709 },
710 BackgroundColor(CRIMSON.into()),
711 children![
712 (
713 RadioGroup,
714 Node {
715 align_items: AlignItems::Center,
716 ..default()
717 },
718 BackgroundColor(CRIMSON.into()),
719 Children::spawn((
720 Spawn((Text::new("Volume"), button_text_style.clone())),
721 SpawnWith(move |parent: &mut ChildSpawner| {
722 for volume_setting in [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] {
723 let mut entity = parent.spawn((
724 RadioButton,
725 Node {
726 width: px(30),
727 height: px(65),
728 ..button_node_clone.clone()
729 },
730 BackgroundColor(NORMAL_BUTTON),
731 Setting(Volume(volume_setting)),
732 ));
733 if volume == Volume(volume_setting) {
734 entity.insert((Checked, BackgroundColor(PRESSED_BUTTON)));
735 }
736 }
737 })
738 ))
739 ),
740 (
741 Button,
742 ActivateOnPress,
743 button_node,
744 BackgroundColor(NORMAL_BUTTON),
745 MenuButtonAction::BackToSettings,
746 children![(Text::new("Back"), button_text_style)]
747 )
748 ]
749 )],
750 ));
751 }208fn setup(mut commands: Commands) {
209 commands.spawn(Camera2d);
210}
211
212fn setup_menu(mut commands: Commands) {
213 commands.spawn((
214 DespawnOnExit(GameState::Menu),
215 Node {
216 width: percent(100),
217 height: percent(100),
218 flex_direction: FlexDirection::Column,
219 justify_content: JustifyContent::Center,
220 align_items: AlignItems::Center,
221 row_gap: px(20),
222 ..default()
223 },
224 children![
225 (Text::new("Bevy Mines"), TextFont::from_font_size(35.0)),
226 (
227 Node {
228 flex_direction: FlexDirection::Column,
229 row_gap: px(10),
230 ..default()
231 },
232 children![
233 text_button("easy", ButtonAction::NewGame(Difficulty::Easy)),
234 text_button("normal", ButtonAction::NewGame(Difficulty::Normal)),
235 text_button("hard", ButtonAction::NewGame(Difficulty::Hard)),
236 ],
237 ),
238 ],
239 ));
240}
241
242fn setup_game(mut commands: Commands, game: Res<Game>, assets: Res<AssetServer>) {
243 let root = commands
244 .spawn((
245 GameRoot,
246 DespawnOnExit(GameState::Playing),
247 Node {
248 margin: auto().all(),
249 ..default()
250 },
251 ))
252 .id();
253
254 rebuild_game_ui(&mut commands, root, &game, &assets);
255}218fn setup(mut commands: Commands) {
219 commands.spawn(Camera2d);
220}
221
222fn setup_game(mut commands: Commands, asset_server: Res<AssetServer>) {
223 commands.spawn(Sprite::from_image(asset_server.load("branding/icon.png")));
224 commands.spawn_scene(bsn! {
225 Node {
226 width: percent(100),
227 height: percent(100),
228 }
229 Children [
230 Node {
231 position_type: PositionType::Absolute,
232 left: px(10),
233 top: px(10),
234 }
235 Children [
236 Text("Move with arrow keys.")
237 ]
238 --
239 Node {
240 position_type: PositionType::Absolute,
241 left: px(10),
242 bottom: px(10),
243 padding: px(5),
244 justify_content: JustifyContent::Center,
245 align_items: AlignItems::Center,
246 }
247 Button
248 Hovered::default()
249 BackgroundColor(NORMAL_BUTTON)
250 on(|event: On<Add<Pressed>>,
251 mut commands: Commands| {
252 commands.entity(event.entity).insert(BackgroundColor(PRESSED_BUTTON));
253 })
254 on(|event: On<Remove<Pressed>>,
255 is_hovered: Query<&Hovered>,
256 mut commands: Commands| {
257 if is_hovered.get(event.entity).is_ok_and(Hovered::get) {
258 commands.entity(event.entity).insert(BackgroundColor(HOVERED_BUTTON));
259 } else {
260 commands.entity(event.entity).insert(BackgroundColor(NORMAL_BUTTON));
261 }
262 })
263 Children [
264 Text("Restart Game")
265 TextFont {
266 font_size: FontSize::Px(33.0),
267 }
268 TextColor(Color::srgb(0.9, 0.9, 0.9))
269 ]
270 ]
271 });
272 info!("Setup game");
273}
274
275fn teardown_game(mut commands: Commands, player: Single<Entity, With<Sprite>>) {
276 commands.entity(*player).despawn();
277 info!("Teardown game");
278}
279
280#[derive(Resource)]
281struct MenuData {
282 pub button_entity: Entity,
283}
284
285const NORMAL_BUTTON: Color = Color::srgb(0.15, 0.15, 0.15);
286const HOVERED_BUTTON: Color = Color::srgb(0.25, 0.25, 0.25);
287const PRESSED_BUTTON: Color = Color::srgb(0.35, 0.75, 0.35);
288
289fn setup_menu(mut commands: Commands) {
290 let button_entity = commands
291 .spawn((
292 Node {
293 // center button
294 width: percent(100),
295 height: percent(100),
296 justify_content: JustifyContent::Center,
297 align_items: AlignItems::Center,
298 ..default()
299 },
300 children![(
301 Button,
302 ActivateOnPress,
303 Hovered::default(),
304 Node {
305 width: px(150),
306 height: px(65),
307 // horizontally center child text
308 justify_content: JustifyContent::Center,
309 // vertically center child text
310 align_items: AlignItems::Center,
311 ..default()
312 },
313 BackgroundColor(NORMAL_BUTTON),
314 children![(
315 Text::new("Play"),
316 TextFont {
317 font_size: FontSize::Px(33.0),
318 ..default()
319 },
320 TextColor(Color::srgb(0.9, 0.9, 0.9)),
321 )]
322 )],
323 ))
324 .id();
325 commands.insert_resource(MenuData { button_entity });
326}57fn setup(mut commands: Commands) {
58 commands.spawn(Camera2d);
59}
60
61fn setup_menu(mut commands: Commands) {
62 let button_entity = commands
63 .spawn((
64 Node {
65 // center button
66 width: percent(100),
67 height: percent(100),
68 justify_content: JustifyContent::Center,
69 align_items: AlignItems::Center,
70 ..default()
71 },
72 children![(
73 Button,
74 ActivateOnPress,
75 Hovered::default(),
76 Node {
77 width: px(150),
78 height: px(65),
79 // horizontally center child text
80 justify_content: JustifyContent::Center,
81 // vertically center child text
82 align_items: AlignItems::Center,
83 ..default()
84 },
85 BackgroundColor(NORMAL_BUTTON),
86 children![(
87 Text::new("Play"),
88 TextFont {
89 font_size: FontSize::Px(33.0),
90 ..default()
91 },
92 TextColor(Color::srgb(0.9, 0.9, 0.9)),
93 )],
94 )],
95 ))
96 .id();
97 commands.insert_resource(MenuData { button_entity });
98}
99
100fn on_activate_start_game(_: On<Activate>, mut next_state: ResMut<NextState<AppState>>) {
101 next_state.set(AppState::InGame);
102}
103
104fn hover_style(
105 mut button_query: Query<(&Hovered, &mut BackgroundColor), (Changed<Hovered>, With<Button>)>,
106) {
107 for (hovered, mut color) in &mut button_query {
108 if hovered.get() {
109 *color = HOVERED_BUTTON.into();
110 } else {
111 *color = NORMAL_BUTTON.into();
112 }
113 }
114}
115
116fn cleanup_menu(mut commands: Commands, menu_data: Res<MenuData>) {
117 commands.entity(menu_data.button_entity).despawn();
118}
119
120fn setup_game(mut commands: Commands, asset_server: Res<AssetServer>) {
121 commands.spawn(Sprite::from_image(asset_server.load("branding/icon.png")));
122}- examples/2d/sprite_scale.rs
- examples/gizmos/anchored_text_gizmos.rs
- examples/gizmos/text_gizmos_font.rs
- examples/window/window_resizing.rs
- examples/state/computed_states.rs
- examples/state/sub_states.rs
- examples/app/without_winit.rs
- examples/window/custom_cursor_image.rs
- examples/ecs/custom_query_param.rs
- examples/ecs/system_param.rs
- examples/stress_tests/many_text.rs
- examples/3d/irradiance_volumes.rs
- examples/asset/asset_saving_with_subassets.rs
- examples/ui/widgets/standard_widgets.rs
- examples/ui/widgets/standard_widgets_observers.rs
- examples/ecs/one_shot_systems.rs
- examples/audio/audio.rs
- examples/asset/custom_asset_reader.rs
- examples/window/transparent_window.rs
- examples/ecs/extraction.rs
- tests/3d/test_skinned_mesh_bounds.rs
- examples/3d/mixed_lighting.rs
- examples/time/timers.rs
- examples/2d/sprite.rs
- examples/gizmos/2d_text_gizmos.rs
- examples/asset/asset_decompression.rs
- examples/ecs/removal_detection.rs
- examples/3d/reflection_probes.rs
- examples/2d/move_sprite.rs
- examples/2d/rotate_to_cursor.rs
- examples/3d/light_probe_blending.rs
- examples/app/logs.rs
- examples/audio/decodable.rs
- examples/app/log_layers_ecs.rs
- examples/ecs/change_detection.rs
- examples/camera/pan_camera_controller.rs
- examples/3d/fog.rs
- examples/asset/multi_asset_sync.rs
- examples/gltf/gltf_extension_mesh_2d.rs
- examples/audio/play_sound_effect.rs
- examples/ecs/delayed_commands.rs
- examples/gizmos/3d_text_gizmos.rs
- examples/shader/sprite_material.rs
- examples/2d/mesh2d.rs
- examples/2d/dynamic_mip_generation.rs
- examples/asset/web_asset.rs
- examples/ecs/component_hooks.rs
- examples/2d/sprite_flipping.rs
- examples/window/persisting_window_settings.rs
- examples/window/screenshot.rs
- examples/movement/physics_in_fixed_timestep.rs
- examples/camera/2d_screen_shake.rs
- examples/async_tasks/async_channel_pattern.rs
- examples/math/render_primitives.rs
- examples/gltf/gltf_extension_animation_graph.rs
- examples/ecs/generic_system.rs
- examples/ui/navigation/directional_navigation.rs
- examples/stress_tests/many_gizmos.rs
- examples/scene/world_serialization.rs
- examples/gltf/gltf_skinned_mesh.rs
- examples/showcase/alien_cake_addict.rs
- examples/3d/mirror.rs
- examples/shader/gpu_readback.rs
- examples/3d/pccm.rs
- examples/shader/animate_shader.rs
- examples/async_tasks/async_compute.rs
- examples/ecs/state_scoped.rs
- examples/audio/pitch.rs
- examples/ecs/observer_propagation.rs
- examples/2d/sprite_tile.rs
- examples/gltf/query_gltf_primitives.rs
- examples/3d/lightmaps.rs
- examples/shader/shader_material_2d.rs
- examples/shader_advanced/render_depth_to_texture.rs
- examples/ecs/fallible_params.rs
- examples/3d/ssr.rs
- examples/gltf/custom_gltf_vertex_attribute.rs
- examples/ecs/ecs_guide.rs
- examples/camera/2d_top_down_camera.rs
- examples/2d/pixel_grid_snap.rs
- examples/shader/fallback_image.rs
- examples/shader_advanced/custom_phase_item.rs
- examples/3d/motion_blur.rs
- examples/ecs/hotpatching_systems.rs
- examples/3d/3d_viewport_to_world.rs
- examples/camera/free_camera_controller.rs
- examples/dev_tools/fps_overlay.rs
- examples/3d/clustered_decals.rs
- examples/shader/pipeline_constants.rs
- examples/shader/shader_material.rs
- examples/usage/context_menu.rs
- examples/asset/extra_source.rs
- examples/shader_advanced/texture_binding_array.rs
- examples/remote/app_under_test.rs
- examples/ui/scroll_and_overflow/scrollbars.rs
- examples/ui/window_fallthrough.rs
- examples/app/externally_driven_headless_renderer.rs
- examples/asset/hot_asset_reloading.rs
- examples/ecs/parallel_query.rs
- examples/reflection/mutation_by_reflection.rs
- examples/shader_advanced/manual_material.rs
- examples/3d/light_textures.rs
- examples/audio/audio_control.rs
- examples/async_tasks/external_source_external_thread.rs
- examples/gizmos/2d_gizmos.rs
- examples/3d/color_grading.rs
- examples/2d/transparency_2d.rs
- examples/showcase/loading_screen.rs
- examples/transforms/3d_rotation.rs
- examples/shader_advanced/mesh_shader_intro.rs
- examples/transforms/scale.rs
- examples/camera/pan_orbit_camera_minimal.rs
- examples/ecs/entity_disabling.rs
- examples/shader_advanced/custom_vertex_attribute.rs
- examples/shader_advanced/fullscreen_material.rs
- examples/ui/text/font_atlas_debug.rs
- examples/animation/morph_targets.rs
- tests/window/minimizing.rs
- tests/window/resizing.rs
- examples/3d/atmospheric_fog.rs
- examples/transforms/translation.rs
- examples/shader/shader_defs.rs
- examples/ui/widgets/button.rs
- examples/gltf/load_gltf_extras.rs
- examples/shader/compute_shader_game_of_life.rs
- examples/asset/embedded_asset.rs
- examples/usage/cooldown.rs
- examples/window/scale_factor_override.rs
- examples/2d/sprite_sheet.rs
- examples/window/window_drag_move.rs
- examples/3d/tonemapping.rs
- examples/3d/parenting.rs
- examples/animation/animation_graph.rs
- examples/3d/post_processing.rs
- examples/3d/rotate_environment_map.rs
- examples/app/settings.rs
- examples/shader/shader_material_screenspace_texture.rs
- examples/3d/depth_of_field.rs
- examples/ui/images/image_node.rs
- examples/ui/text/editable_text_filter.rs
- examples/camera/camera_orbit.rs
- examples/shader/shader_material_bindless.rs
- examples/gltf/edit_material_on_gltf.rs
- examples/remote/server.rs
- examples/audio/soundtrack.rs
- examples/animation/animation_masks.rs
- examples/ui/layout/fixed_node.rs
- examples/3d/animated_material.rs
- examples/3d/pcss.rs
- examples/shader_advanced/custom_post_processing.rs
- examples/3d/clearcoat.rs
- examples/3d/anisotropy.rs
- examples/camera/custom_projection.rs
- examples/animation/animated_mesh_events.rs
- examples/picking/custom_hit_data.rs
- examples/gltf/load_gltf.rs
- examples/3d/two_passes.rs
- examples/diagnostics/log_diagnostics.rs
- examples/animation/animated_mesh.rs
- examples/stress_tests/many_materials.rs
- examples/shader/shader_material_2d_bindless.rs
- examples/stress_tests/many_glyphs.rs
- examples/shader/extended_material_bindless.rs
- examples/3d/clustered_decal_maps.rs
- examples/dev_tools/infinite_grid.rs
- examples/gltf/update_gltf_scene.rs
- examples/shader/gpu_component_array_buffer.rs
- examples/stress_tests/text_pipeline.rs
- examples/3d/skybox.rs
- examples/3d/fog_volumes.rs
- examples/3d/lines.rs
- examples/shader_advanced/deferred_raymarch.rs
- examples/shader/storage_buffer.rs
- examples/window/low_power.rs
- examples/2d/mesh2d_vertex_color_texture.rs
- examples/shader/array_texture.rs
- examples/3d/generate_custom_mesh.rs
- examples/ui/text/inline_image.rs
- examples/3d/mesh_ray_cast.rs
- examples/picking/simple_picking.rs
- examples/stress_tests/many_sprites.rs
- examples/animation/color_animation.rs
- examples/audio/spatial_audio_2d.rs
- examples/movement/smooth_follow.rs
- examples/2d/tilemap_chunk.rs
- examples/ui/relative_cursor_position.rs
- examples/shader/extended_material.rs
- examples/ui/ui_material.rs
- examples/3d/vertex_colors.rs
- examples/animation/animated_mesh_control.rs
- examples/animation/animation_events.rs
- examples/asset/generated_assets.rs
- examples/shader_advanced/custom_shader_instancing.rs
- tests/window/desktop_request_redraw.rs
- examples/ui/text/font_weights.rs
- examples/3d/orthographic.rs
- examples/picking/debug_picking.rs
- examples/showcase/contributors.rs
- examples/testbed/2d.rs
- examples/window/multiple_windows.rs
- examples/ui/ui_scaling.rs
- examples/3d/spherical_area_lights.rs
- examples/stress_tests/many_meshlet_materials.rs
- examples/math/bounding_2d.rs
- examples/2d/2d_viewport_to_world.rs
- examples/transforms/transform.rs
- examples/ui/images/ui_texture_atlas.rs
- examples/stress_tests/many_animated_sprites.rs
- examples/2d/bloom_2d.rs
- examples/stress_tests/many_morph_targets.rs
- examples/ui/text/font_variations.rs
- examples/camera/first_person_view_model.rs
- examples/ecs/observers.rs
- examples/gizmos/axes.rs
- examples/app/headless_renderer.rs
- examples/ui/layout/size_constraints.rs
- examples/ecs/relationships.rs
- examples/3d/occlusion_culling.rs
- examples/3d/specular_tint.rs
- examples/3d/ssao.rs
- examples/ui/widgets/viewport_node.rs
- examples/animation/animated_ui.rs
- examples/ui/scroll_and_overflow/overflow_debug.rs
- examples/3d/atmosphere.rs
- examples/app/render_recovery.rs
- examples/stress_tests/many_text2d.rs
- examples/animation/eased_motion.rs
- examples/stress_tests/many_buttons.rs
- examples/camera/pan_orbit_camera_cad.rs
- examples/shader_advanced/custom_render_phase.rs
- examples/stress_tests/many_gradients.rs
- examples/stress_tests/transform_hierarchy.rs
- examples/audio/spatial_audio_3d.rs
- examples/asset/alter_sprite.rs
- examples/shader/automatic_instancing.rs
- examples/ui/text/text_input.rs
- examples/ecs/error_handling.rs
- examples/camera/projection_zoom.rs
- examples/2d/rotation.rs
- examples/2d/wireframe_2d.rs
- examples/3d/rect_light.rs
- examples/camera/2d_on_ui.rs
- examples/ui/images/ui_texture_slice.rs
- examples/3d/visibility_range.rs
- examples/2d/sprite_animation.rs
- examples/math/cubic_splines.rs
- examples/window/monitor_info.rs
- examples/ui/text/ime_support.rs
- examples/3d/volumetric_fog.rs
- examples/2d/tilemap_chunk_orientation.rs
- examples/2d/cpu_draw.rs
- tests/3d/test_invalid_skinned_mesh.rs
- examples/ecs/callbacks.rs
- examples/3d/texture.rs
- examples/stress_tests/many_cameras_lights.rs
- examples/time/virtual_time.rs
- examples/shader_advanced/specialized_mesh_pipeline.rs
- examples/ui/text/text_background_colors.rs
- examples/ui/images/ui_texture_slice_flip_and_tile.rs
- examples/3d/shadow_caster_receiver.rs
- examples/3d/wireframe.rs
- examples/3d/bloom_3d.rs
- examples/stress_tests/many_lights.rs
- examples/3d/anti_aliasing.rs
- examples/testbed/ui.rs
- examples/ui/text/generic_font_families.rs
- examples/camera/pan_orbit_camera_ortho.rs
- examples/picking/dragdrop_picking.rs
- examples/transforms/align.rs
- examples/ui/layout/anchor_layout.rs
- examples/math/random_sampling.rs
- examples/testbed/3d.rs
- examples/gizmos/3d_gizmos.rs
- examples/picking/sprite_picking.rs
- examples/ui/images/ui_texture_atlas_slice.rs
- examples/showcase/stepping.rs
- examples/ui/layout/display_and_visibility.rs
- examples/2d/mesh2d_alpha_mode.rs
- examples/2d/mesh2d_arcs.rs
- examples/3d/scrolling_fog.rs
- examples/3d/order_independent_transparency.rs
- examples/ecs/iter_combinations.rs
- examples/shader_advanced/compute_mesh.rs
- examples/ui/text/text_wrap_debug.rs
- examples/3d/render_to_texture.rs
- examples/2d/mesh2d_manual.rs
- examples/2d/sprite_slice.rs
- examples/ui/styling/stacked_gradients.rs
- examples/ui/styling/transparency_ui.rs
- examples/3d/transparency_3d.rs
- examples/asset/repeated_texture.rs
- examples/asset/asset_saving.rs
- examples/asset/asset_settings.rs
- examples/2d/mesh2d_repeated_texture.rs
- examples/3d/spotlight.rs
- examples/asset/alter_mesh.rs
- examples/3d/meshlet.rs
- examples/ui/text/system_fonts.rs
- examples/3d/pbr.rs
- examples/ui/ui_target_camera.rs
- examples/math/custom_primitives.rs
- examples/3d/auto_exposure.rs
- examples/animation/easing_functions.rs
- examples/asset/asset_loading.rs
- examples/window/multi_window_text.rs
- examples/ui/scroll_and_overflow/overflow.rs
- examples/ui/scroll_and_overflow/overflow_clip_margin.rs
- examples/gizmos/light_gizmos.rs
- examples/ui/layout/flex_layout.rs
- examples/shader/shader_prepass.rs
- examples/stress_tests/bevymark_3d.rs
- examples/ui/widgets/vertical_slider.rs
- examples/stress_tests/bevymark.rs
- examples/2d/2d_shapes.rs
- examples/3d/split_screen.rs
- examples/ui/render_ui_to_texture.rs
- examples/gizmos/transform_gizmo.rs
- examples/3d/shadow_biases.rs
- examples/3d/solari_reflections.rs
- examples/ui/widgets/tab_navigation.rs
- examples/ui/scroll_and_overflow/drag_to_scroll.rs
- examples/ui/scroll_and_overflow/scroll.rs
- examples/3d/solari.rs
- examples/showcase/breakout.rs
- examples/3d/decal.rs
- examples/picking/mesh_picking.rs
- examples/ui/layout/z_index.rs
- examples/ui/images/image_node_resizing.rs
- examples/ui/text/strikethrough_and_underline.rs
- examples/ui/scroll_and_overflow/overflow_transform.rs
- examples/showcase/desk_toy.rs
- examples/3d/parallax_mapping.rs
- examples/2d/texture_atlas.rs
- examples/stress_tests/many_foxes.rs
- examples/ui/ui_drag_and_drop.rs
- examples/3d/deferred_rendering.rs
- examples/ui/text/text.rs
- examples/3d/contact_shadows.rs
- examples/2d/text2d.rs
- examples/3d/3d_shapes.rs
- examples/animation/custom_skinned_mesh.rs
- examples/usage/debug_frustum_culling.rs
- examples/3d/blend_modes.rs
- examples/animation/animated_transform.rs
- examples/ui/navigation/directional_navigation_overrides.rs
- examples/3d/lighting.rs
- examples/picking/draggable_slider.rs
- examples/ui/text/letter_spacing.rs
- examples/3d/camera_sub_view.rs
- examples/ui/text/text_debug.rs
- examples/ui/styling/gradients.rs
- examples/ui/layout/grid.rs
- examples/3d/transmission.rs
- examples/stress_tests/many_cubes.rs
- examples/ui/text/multiple_text_inputs.rs
- examples/ui/ui_transform.rs
- examples/ui/styling/borders.rs
- examples/ui/text/font_query.rs
- examples/testbed/full_ui.rs
- examples/ui/text/multiline_text_input.rs
Sourcepub fn entity(&mut self, entity: Entity) -> EntityCommands<'_>
pub fn entity(&mut self, entity: Entity) -> EntityCommands<'_>
Returns the EntityCommands for the given Entity.
This method does not guarantee that commands queued by the returned EntityCommands
will be successful, since the entity could be despawned before they are executed.
§Example
#[derive(Resource)]
struct PlayerEntity {
entity: Entity
}
#[derive(Component)]
struct Label(&'static str);
fn example_system(mut commands: Commands, player: Res<PlayerEntity>) {
// Get the entity and add a component.
commands.entity(player.entity).insert(Label("hello world"));
}§See also
get_entityfor the fallible version.
Examples found in repository?
167fn cleanup_menu(mut commands: Commands, menu_data: Res<MenuData>) {
168 commands.entity(menu_data.button_entity).despawn();
169}
170
171const SPEED: f32 = 100.0;
172fn movement(
173 time: Res<Time>,
174 input: Res<ButtonInput<KeyCode>>,
175 mut query: Query<&mut Transform, With<Sprite>>,
176) {
177 for mut transform in &mut query {
178 let mut direction = Vec3::ZERO;
179 if input.pressed(KeyCode::ArrowLeft) {
180 direction.x -= 1.0;
181 }
182 if input.pressed(KeyCode::ArrowRight) {
183 direction.x += 1.0;
184 }
185 if input.pressed(KeyCode::ArrowUp) {
186 direction.y += 1.0;
187 }
188 if input.pressed(KeyCode::ArrowDown) {
189 direction.y -= 1.0;
190 }
191
192 if direction != Vec3::ZERO {
193 transform.translation += direction.normalize() * SPEED * time.delta_secs();
194 }
195 }
196}
197
198fn change_color(time: Res<Time>, mut query: Query<&mut Sprite>) {
199 for mut sprite in &mut query {
200 let new_color = LinearRgba {
201 blue: ops::sin(time.elapsed_secs() * 0.5) + 2.0,
202 ..LinearRgba::from(sprite.color)
203 };
204
205 sprite.color = new_color.into();
206 }
207}
208
209// We can restart the game by pressing the restart button.
210// This will trigger an [`AppState::InGame`] -> [`AppState::InGame`]
211// transition, which will run our custom schedules.
212fn trigger_game_restart(_: On<Activate>, mut next_state: ResMut<NextState<AppState>>) {
213 // Although we are already in this state setting it again will generate an identity transition.
214 // While default schedules ignore those kinds of transitions, our custom schedules will react to them.
215 next_state.set(AppState::InGame);
216}
217
218fn setup(mut commands: Commands) {
219 commands.spawn(Camera2d);
220}
221
222fn setup_game(mut commands: Commands, asset_server: Res<AssetServer>) {
223 commands.spawn(Sprite::from_image(asset_server.load("branding/icon.png")));
224 commands.spawn_scene(bsn! {
225 Node {
226 width: percent(100),
227 height: percent(100),
228 }
229 Children [
230 Node {
231 position_type: PositionType::Absolute,
232 left: px(10),
233 top: px(10),
234 }
235 Children [
236 Text("Move with arrow keys.")
237 ]
238 --
239 Node {
240 position_type: PositionType::Absolute,
241 left: px(10),
242 bottom: px(10),
243 padding: px(5),
244 justify_content: JustifyContent::Center,
245 align_items: AlignItems::Center,
246 }
247 Button
248 Hovered::default()
249 BackgroundColor(NORMAL_BUTTON)
250 on(|event: On<Add<Pressed>>,
251 mut commands: Commands| {
252 commands.entity(event.entity).insert(BackgroundColor(PRESSED_BUTTON));
253 })
254 on(|event: On<Remove<Pressed>>,
255 is_hovered: Query<&Hovered>,
256 mut commands: Commands| {
257 if is_hovered.get(event.entity).is_ok_and(Hovered::get) {
258 commands.entity(event.entity).insert(BackgroundColor(HOVERED_BUTTON));
259 } else {
260 commands.entity(event.entity).insert(BackgroundColor(NORMAL_BUTTON));
261 }
262 })
263 Children [
264 Text("Restart Game")
265 TextFont {
266 font_size: FontSize::Px(33.0),
267 }
268 TextColor(Color::srgb(0.9, 0.9, 0.9))
269 ]
270 ]
271 });
272 info!("Setup game");
273}
274
275fn teardown_game(mut commands: Commands, player: Single<Entity, With<Sprite>>) {
276 commands.entity(*player).despawn();
277 info!("Teardown game");
278}More examples
- examples/ecs/generic_system.rs
- examples/usage/context_menu.rs
- examples/ui/widgets/headless_tabs.rs
- examples/ui/navigation/directional_navigation.rs
- examples/showcase/loading_screen.rs
- examples/ecs/contiguous_query.rs
- examples/ecs/removal_detection.rs
- examples/ui/widgets/standard_widgets_observers.rs
- examples/async_tasks/external_source_external_thread.rs
- examples/3d/volumetric_fog.rs
- examples/asset/multi_asset_sync.rs
- examples/shader/gpu_component_array_buffer.rs
- examples/ecs/one_shot_systems.rs
- examples/gizmos/transform_gizmo.rs
- examples/ecs/extraction.rs
- examples/window/screenshot.rs
- examples/3d/color_grading.rs
- examples/3d/reflection_probes.rs
- examples/3d/depth_of_field.rs
- examples/ui/widgets/tab_navigation.rs
- examples/ecs/observer_propagation.rs
- examples/animation/animation_graph.rs
- examples/ecs/entity_disabling.rs
- examples/shader_advanced/custom_shader_instancing.rs
- examples/3d/pbr.rs
- examples/asset/asset_decompression.rs
- examples/shader_advanced/fullscreen_material.rs
- examples/shader/sprite_material.rs
- examples/asset/asset_saving.rs
- examples/animation/morph_targets.rs
- examples/app/log_layers_ecs.rs
- examples/usage/cooldown.rs
- examples/picking/dragdrop_picking.rs
- examples/animation/animated_mesh_control.rs
- tests/3d/test_meshlet.rs
- examples/ecs/error_handling.rs
- examples/window/window_settings.rs
- examples/testbed/3d.rs
- tests/3d/test_skinned_mesh_bounds.rs
- examples/showcase/game_menu.rs
- examples/ui/widgets/standard_widgets.rs
- examples/3d/anisotropy.rs
- examples/gltf/gltf_extension_animation_graph.rs
- examples/3d/clearcoat.rs
- examples/asset/asset_saving_with_subassets.rs
- examples/3d/tonemapping.rs
- examples/3d/ssr.rs
- examples/3d/pccm.rs
- examples/ecs/delayed_commands.rs
- examples/3d/irradiance_volumes.rs
- examples/3d/shadow_caster_receiver.rs
- examples/ui/layout/display_and_visibility.rs
- examples/3d/mirror.rs
- examples/audio/soundtrack.rs
- examples/3d/pcss.rs
- examples/ui/styling/box_shadow.rs
- examples/ecs/fallible_params.rs
- examples/showcase/stepping.rs
- examples/usage/character_creation.rs
- examples/ui/widgets/feathers_number_input.rs
- examples/3d/clustered_decals.rs
- examples/window/custom_cursor_image.rs
- examples/2d/dynamic_mip_generation.rs
- examples/3d/solari_reflections.rs
- examples/3d/lightmaps.rs
- tests/window/desktop_request_redraw.rs
- examples/animation/animated_mesh.rs
- examples/camera/pan_orbit_camera_cad.rs
- examples/3d/visibility_range.rs
- examples/ecs/hierarchy.rs
- examples/3d/light_textures.rs
- examples/math/bounding_2d.rs
- examples/ecs/relationships.rs
- examples/3d/occlusion_culling.rs
- examples/animation/eased_motion.rs
- examples/3d/clustered_decal_maps.rs
- examples/shader_advanced/custom_post_processing.rs
- examples/showcase/alien_cake_addict.rs
- examples/ui/text/text_input.rs
- examples/showcase/breakout.rs
- examples/gltf/edit_material_on_gltf.rs
- examples/ui/layout/size_constraints.rs
- examples/window/monitor_info.rs
- examples/animation/animated_mesh_events.rs
- examples/async_tasks/async_compute.rs
- examples/3d/light_probe_blending.rs
- examples/3d/blend_modes.rs
- examples/stress_tests/many_morph_targets.rs
- examples/3d/order_independent_transparency.rs
- examples/math/random_sampling.rs
- examples/stress_tests/transform_hierarchy.rs
- examples/ui/text/text_wrap_debug.rs
- examples/state/computed_states.rs
- examples/animation/animation_masks.rs
- examples/3d/deferred_rendering.rs
- examples/3d/solari.rs
- examples/testbed/ui.rs
- examples/3d/mixed_lighting.rs
- examples/diagnostics/log_diagnostics.rs
- examples/ecs/component_hooks.rs
- examples/ui/scroll_and_overflow/scroll.rs
- tests/3d/test_invalid_skinned_mesh.rs
- examples/3d/ssao.rs
- examples/3d/bloom_3d.rs
- examples/2d/bloom_2d.rs
- examples/stress_tests/many_foxes.rs
- examples/3d/contact_shadows.rs
- examples/3d/anti_aliasing.rs
- examples/animation/custom_skinned_mesh.rs
- examples/animation/animated_transform.rs
- examples/ui/navigation/directional_navigation_overrides.rs
- examples/showcase/mines.rs
- examples/ui/text/text_debug.rs
- examples/3d/transmission.rs
- examples/ui/widgets/feathers_gallery.rs
Sourcepub fn get_entity(
&mut self,
entity: Entity,
) -> Result<EntityCommands<'_>, InvalidEntityError>
pub fn get_entity( &mut self, entity: Entity, ) -> Result<EntityCommands<'_>, InvalidEntityError>
Returns the EntityCommands for the requested Entity if it is valid.
This method does not guarantee that commands queued by the returned EntityCommands
will be successful, since the entity could be despawned before they are executed.
This also does not error when the entity has not been spawned.
For that behavior, see get_spawned_entity,
which should be preferred for accessing entities you expect to already be spawned, like those found from a query.
For details on entity spawning vs validity, see entity module docs.
§Errors
Returns InvalidEntityError if the requested entity does not exist.
§Example
#[derive(Resource)]
struct PlayerEntity {
entity: Entity
}
#[derive(Component)]
struct Label(&'static str);
fn example_system(mut commands: Commands, player: Res<PlayerEntity>) -> Result {
// Get the entity if it still exists and store the `EntityCommands`.
// If it doesn't exist, the `?` operator will propagate the returned error
// to the system, and the system will pass it to an error handler.
let mut entity_commands = commands.get_entity(player.entity)?;
// Add a component to the entity.
entity_commands.insert(Label("hello world"));
// Return from the system successfully.
Ok(())
}§See also
entityfor the infallible version.
Examples found in repository?
163fn explode_mine(explode: On<Explode>, query: Query<&Mine>, mut commands: Commands) {
164 // Explode is an EntityEvent. `explode.entity` is the entity that Explode was triggered for.
165 let Ok(mut entity) = commands.get_entity(explode.entity) else {
166 return;
167 };
168 info!("Boom! {} exploded.", explode.entity);
169 entity.despawn();
170 let mine = query.get(explode.entity).unwrap();
171 // Trigger another explosion cascade.
172 commands.trigger(ExplodeMines {
173 pos: mine.pos,
174 radius: mine.size,
175 });
176}Sourcepub fn get_spawned_entity(
&mut self,
entity: Entity,
) -> Result<EntityCommands<'_>, EntityNotSpawnedError>
pub fn get_spawned_entity( &mut self, entity: Entity, ) -> Result<EntityCommands<'_>, EntityNotSpawnedError>
Returns the EntityCommands for the requested Entity if it spawned in the world now.
Note that for entities that have not been spawned yet, like ones from spawn, this will error.
If that is not desired, try get_entity.
This should be used over get_entity when you expect the entity to already be spawned in the world.
If the entity is valid but not yet spawned, this will error that information, where get_entity would succeed, leading to potentially surprising results.
For details on entity spawning vs validity, see entity module docs.
This method does not guarantee that commands queued by the returned EntityCommands
will be successful, since the entity could be despawned before they are executed.
§Errors
Returns EntityNotSpawnedError if the requested entity does not exist.
§Example
#[derive(Resource)]
struct PlayerEntity {
entity: Entity
}
#[derive(Component)]
struct Label(&'static str);
fn example_system(mut commands: Commands, player: Res<PlayerEntity>) -> Result {
// Get the entity if it still exists and store the `EntityCommands`.
// If it doesn't exist, the `?` operator will propagate the returned error
// to the system, and the system will pass it to an error handler.
let mut entity_commands = commands.get_spawned_entity(player.entity)?;
// Add a component to the entity.
entity_commands.insert(Label("hello world"));
// Return from the system successfully.
Ok(())
}§See also
entityfor the infallible version.
Sourcepub fn spawn_batch<I>(&mut self, batch: I)where
I: IntoIterator + Send + Sync + 'static,
<I as IntoIterator>::Item: Bundle,
<<I as IntoIterator>::Item as DynamicBundle>::Effect: NoBundleEffect,
pub fn spawn_batch<I>(&mut self, batch: I)where
I: IntoIterator + Send + Sync + 'static,
<I as IntoIterator>::Item: Bundle,
<<I as IntoIterator>::Item as DynamicBundle>::Effect: NoBundleEffect,
Spawns multiple entities with the same combination of components,
based on a batch of Bundles.
A batch can be any type that implements IntoIterator and contains bundles,
such as a Vec<Bundle> or an array [Bundle; N].
This method is equivalent to iterating the batch
and calling spawn for each bundle,
but is faster by pre-allocating memory and having exclusive World access.
§Example
use bevy_ecs::prelude::*;
#[derive(Component)]
struct Score(u32);
fn example_system(mut commands: Commands) {
commands.spawn_batch([
(Name::new("Alice"), Score(0)),
(Name::new("Bob"), Score(0)),
]);
}§See also
spawnto spawn an entity with components.spawn_emptyto spawn an entity without components.
Examples found in repository?
More examples
183fn startup_system(mut commands: Commands, mut game_state: ResMut<GameState>) {
184 // Create our game rules resource
185 commands.insert_resource(GameRules {
186 max_rounds: 10,
187 winning_score: 4,
188 max_players: 4,
189 });
190
191 // Add some players to our world. Players start with a score of 0 ... we want our game to be
192 // fair!
193 commands.spawn_batch(vec![
194 (
195 Player {
196 name: "Alice".to_string(),
197 },
198 Score { value: 0 },
199 PlayerStreak::None,
200 ),
201 (
202 Player {
203 name: "Bob".to_string(),
204 },
205 Score { value: 0 },
206 PlayerStreak::None,
207 ),
208 ]);
209
210 // set the total players to "2"
211 game_state.total_players = 2;
212}580fn spawn_auto_instancing_test(commands: &mut Commands, resources: &mut SceneResources) {
581 let meshes = &mut resources.meshes;
582 let materials = &mut resources.materials;
583 let asset_server = &mut resources.asset_server;
584
585 let cube = meshes.add(Cuboid::new(1.0, 1.0, 1.0));
586 let material_handle = materials.add(StandardMaterial {
587 alpha_mode: AlphaMode::Blend,
588 base_color_texture: Some(asset_server.load("textures/slice_square.png")),
589 ..Default::default()
590 });
591 let mut bundles = Vec::with_capacity(3 * 3 * 3);
592
593 for z in -1..=1 {
594 for y in -1..=1 {
595 for x in -1..=1 {
596 bundles.push((
597 Mesh3d(cube.clone()),
598 MeshMaterial3d(material_handle.clone()),
599 Transform::from_xyz(x as f32 * 2.0, y as f32 * 2.0, z as f32 * 2.0),
600 ));
601 }
602 }
603 }
604 commands.spawn_batch(bundles);
605}54fn setup(mut commands: Commands, assets: Res<AssetServer>, color_tint: Res<ColorTint>) {
55 warn!(include_str!("warning_string.txt"));
56
57 let mut rng = rand::rng();
58
59 let tile_size = Vec2::splat(64.0);
60 let map_size = Vec2::splat(320.0);
61
62 let half_x = (map_size.x / 2.0) as i32;
63 let half_y = (map_size.y / 2.0) as i32;
64
65 let sprite_handle = assets.load("branding/icon.png");
66
67 // Spawns the camera
68
69 commands.spawn(Camera2d);
70
71 // Builds and spawns the sprites
72 let mut sprites = vec![];
73 for y in -half_y..half_y {
74 for x in -half_x..half_x {
75 let position = Vec2::new(x as f32, y as f32);
76 let translation = (position * tile_size).extend(rng.random::<f32>());
77 let rotation = Quat::from_rotation_z(rng.random::<f32>());
78 let scale = Vec3::splat(rng.random::<f32>() * 2.0);
79
80 sprites.push((
81 Sprite {
82 image: sprite_handle.clone(),
83 custom_size: Some(tile_size),
84 color: if color_tint.0 {
85 COLORS[rng.random_range(0..3)]
86 } else {
87 Color::WHITE
88 },
89 ..default()
90 },
91 Transform {
92 translation,
93 rotation,
94 scale,
95 },
96 ));
97 }
98 }
99 commands.spawn_batch(sprites);
100}352fn spawn_cubes(
353 commands: &mut Commands,
354 args: &Args,
355 counter: &mut BevyCounter,
356 spawn_count: usize,
357 cube_resources: &mut CubeResources,
358 waves_to_simulate: Option<usize>,
359 wave: usize,
360) {
361 let batch_material = cube_resources.materials[wave % cube_resources.materials.len()].clone();
362
363 let spawn_y = VOLUME_SIZE.y / 2.0 - HALF_CUBE_SIZE;
364 let spawn_z = -VOLUME_SIZE.z / 2.0 + HALF_CUBE_SIZE;
365
366 let batch = (0..spawn_count)
367 .map(|_| {
368 let spawn_pos = Vec3::new(
369 (cube_resources.transform_rng.random::<f32>() - 0.5) * VOLUME_SIZE.x,
370 spawn_y,
371 spawn_z,
372 );
373
374 let (transform, velocity) = cube_velocity_transform(
375 spawn_pos,
376 &mut cube_resources.velocity_rng,
377 waves_to_simulate,
378 FIXED_DELTA_TIME,
379 );
380
381 let material = if args.vary_per_instance {
382 cube_resources
383 .materials
384 .choose(&mut cube_resources.material_rng)
385 .unwrap()
386 .clone()
387 } else {
388 batch_material.clone()
389 };
390
391 (
392 Mesh3d(cube_resources.cube_mesh.clone()),
393 MeshMaterial3d(material),
394 transform,
395 Cube { velocity },
396 )
397 })
398 .collect::<Vec<_>>();
399 commands.spawn_batch(batch);
400
401 counter.count += spawn_count;
402 counter.color = Color::linear_rgb(
403 cube_resources.color_rng.random(),
404 cube_resources.color_rng.random(),
405 cube_resources.color_rng.random(),
406 );
407}110fn setup(mut commands: Commands, font: Res<FontHandle>, args: Res<Args>) {
111 warn!(include_str!("warning_string.txt"));
112
113 let mut rng = ChaCha8Rng::seed_from_u64(42);
114
115 let tile_size = Vec2::splat(64.0);
116 let map_size = Vec2::splat(640.0);
117
118 let half_x = (map_size.x / 4.0) as i32;
119 let half_y = (map_size.y / 4.0) as i32;
120
121 // Spawns the camera
122
123 commands.spawn(Camera2d);
124
125 // Builds and spawns the `Text2d`s, distributing them in a way that ensures a
126 // good distribution of on-screen and off-screen entities.
127 let hinting = if args.hinting {
128 FontHinting::Enabled
129 } else {
130 FontHinting::Disabled
131 };
132 let mut text2ds = vec![];
133 for y in -half_y..half_y {
134 for x in -half_x..half_x {
135 let position = Vec2::new(x as f32, y as f32);
136 let translation = (position * tile_size).extend(rng.random::<f32>());
137 let rotation = Quat::from_rotation_z(rng.random::<f32>());
138 let scale = Vec3::splat(rng.random::<f32>() * 2.0);
139 let color = Hsla::hsl(rng.random_range(0.0..360.0), 0.8, 0.8);
140
141 text2ds.push((
142 Text2d(random_text(&mut rng, &args)),
143 random_text_font(&mut rng, &args, font.0.clone()),
144 TextColor(color.into()),
145 TextLayout::justify(if args.center {
146 Justify::Center
147 } else {
148 Justify::Left
149 }),
150 hinting,
151 Transform {
152 translation,
153 rotation,
154 scale,
155 },
156 ));
157 }
158 }
159
160 if args.no_frustum_culling {
161 let bundles = text2ds.into_iter().map(|bundle| (bundle, NoFrustumCulling));
162 commands.spawn_batch(bundles);
163 } else {
164 commands.spawn_batch(text2ds);
165 }
166}Sourcepub fn despawn_all<F>(&mut self)where
F: QueryFilter,
pub fn despawn_all<F>(&mut self)where
F: QueryFilter,
Despawns all entities matching the given QueryFilter.
This method is equivalent to iterating over all the filtered entities and despawning them one by one, but is faster by allocating far fewer commands.
use bevy_ecs::prelude::*;
#[derive(Component)]
struct PleaseDespawn;
fn despawn_entities(mut commands: Commands) {
commands.despawn_all::<With<PleaseDespawn>>();
}
Sourcepub fn despawn_all_where<D, F>(
&mut self,
cond: impl FnMut(<D as QueryData>::Item<'_, '_>) -> bool + Send + 'static,
)where
D: QueryData,
F: QueryFilter,
pub fn despawn_all_where<D, F>(
&mut self,
cond: impl FnMut(<D as QueryData>::Item<'_, '_>) -> bool + Send + 'static,
)where
D: QueryData,
F: QueryFilter,
Despawns all entities matching the given QueryFilter and condition.
This method is equivalent to iterating over all the filtered entities and despawning them one by one, but is faster by allocating far fewer commands.
use bevy_ecs::prelude::*;
#[derive(Component)]
struct Health(f32);
fn despawn_dead(mut commands: Commands) {
commands.despawn_all_where::<&Health, ()>(|health| health.0 <= 0.0);
}
Sourcepub fn queue(&mut self, command: impl Command)
pub fn queue(&mut self, command: impl Command)
Pushes a generic Command to the command queue.
If the Command returns a Result,
it will be handled using the fallback error handler.
To use a custom error handler, see Commands::queue_handled.
The command can be:
- A custom struct that implements
Command. - A closure or function that matches one of the following signatures:
- A built-in command from the
commandmodule.
§Example
#[derive(Resource, Default)]
struct Counter(u64);
struct AddToCounter(String);
impl Command for AddToCounter {
type Out = Result;
fn apply(self, world: &mut World) -> Result {
let mut counter = world.get_resource_or_insert_with(Counter::default);
let amount: u64 = self.0.parse()?;
counter.0 += amount;
Ok(())
}
}
fn add_three_to_counter_system(mut commands: Commands) {
commands.queue(AddToCounter("3".to_string()));
}
fn add_twenty_five_to_counter_system(mut commands: Commands) {
commands.queue(|world: &mut World| {
let mut counter = world.get_resource_or_insert_with(Counter::default);
counter.0 += 25;
});
}Examples found in repository?
112fn change_count(
113 mut counter: ResMut<Counter>,
114 keyboard: Res<ButtonInput<KeyCode>>,
115 mut commands: Commands,
116) {
117 let mut changed = false;
118 if keyboard.just_pressed(KeyCode::Space) {
119 counter.count += 1;
120 changed = true;
121 }
122 if keyboard.just_pressed(KeyCode::Backspace) || keyboard.just_pressed(KeyCode::Delete) {
123 counter.count -= 1;
124 changed = true;
125 }
126
127 if changed {
128 commands.queue(SaveSettingsDeferred(Duration::from_secs_f32(0.1)));
129 }
130}
131
132fn on_window_close(mut close: MessageReader<WindowCloseRequested>, mut commands: Commands) {
133 // Save settings immediately, then quit.
134 if let Some(_close_event) = close.read().next() {
135 commands.queue(SaveSettingsSync::IfChanged);
136 commands.write_message(AppExit::Success);
137 }
138}More examples
90fn update_window_settings(
91 mut move_events: MessageReader<WindowMoved>,
92 mut resize_events: MessageReader<WindowResized>,
93 windows: Query<&mut Window>,
94 window_settings: ResMut<WindowSettings>,
95 mut commands: Commands,
96) {
97 let Ok(window) = windows.single() else {
98 return;
99 };
100
101 let mut window_changed = false;
102 for _ in move_events.read() {
103 window_changed = true;
104 }
105
106 for _ in resize_events.read() {
107 window_changed = true;
108 }
109
110 if window_changed && store_window_settings(window_settings, window) {
111 commands.queue(SaveSettingsDeferred(Duration::from_secs_f32(0.5)));
112 }
113}
114
115fn store_window_settings(mut window_settings: ResMut<WindowSettings>, window: &Window) -> bool {
116 window_settings.set_if_neq(WindowSettings {
117 position: match window.position {
118 WindowPosition::At(pos) => Some(pos),
119 _ => None,
120 },
121 size: Some(UVec2::new(
122 window.resolution.width() as u32,
123 window.resolution.height() as u32,
124 )),
125 fullscreen: window.mode != WindowMode::Windowed,
126 })
127}
128
129fn on_window_close(mut close: MessageReader<WindowCloseRequested>, mut commands: Commands) {
130 // Save settings immediately, then quit.
131 if let Some(_close_event) = close.read().next() {
132 commands.queue(SaveSettingsSync::IfChanged);
133 commands.write_message(AppExit::Success);
134 }
135}Sourcepub fn queue_handled(
&mut self,
command: impl Command,
error_handler: impl FnOnce(BevyError, ErrorContext) + Send + 'static,
)
pub fn queue_handled( &mut self, command: impl Command, error_handler: impl FnOnce(BevyError, ErrorContext) + Send + 'static, )
Pushes a generic Command to the command queue.
If the Command returns a Result,
the given error_handler will be used to handle error cases.
To implicitly use the fallback error handler, see Commands::queue.
The command can be:
- A custom struct that implements
Command. - A closure or function that matches one of the following signatures:
- A built-in command from the
commandmodule.
§Example
use bevy_ecs::error::warn;
#[derive(Resource, Default)]
struct Counter(u64);
struct AddToCounter(String);
impl Command for AddToCounter {
type Out = Result;
fn apply(self, world: &mut World) -> Result {
let mut counter = world.get_resource_or_insert_with(Counter::default);
let amount: u64 = self.0.parse()?;
counter.0 += amount;
Ok(())
}
}
fn add_three_to_counter_system(mut commands: Commands) {
commands.queue_handled(AddToCounter("3".to_string()), warn);
}
fn add_twenty_five_to_counter_system(mut commands: Commands) {
commands.queue(|world: &mut World| {
let mut counter = world.get_resource_or_insert_with(Counter::default);
counter.0 += 25;
});
}Examples found in repository?
175fn failing_commands(mut commands: Commands) {
176 commands
177 // This entity doesn't exist!
178 .entity(Entity::from_raw_u32(12345678).unwrap())
179 // Normally, this failed command would panic,
180 // but since we've set the fallback error handler to `warn`
181 // it will log a warning instead.
182 .insert(Transform::default());
183
184 // The error handlers for commands can be set individually as well,
185 // by using the queue_handled method.
186 commands.queue_handled(
187 |world: &mut World| -> Result {
188 world
189 .get_resource::<UninitializedResource>()
190 .ok_or("Resource not initialized when accessed in a command")?;
191
192 Ok(())
193 },
194 |error, context| {
195 error!("{error}, {context}");
196 },
197 );
198}Sourcepub fn queue_silenced(&mut self, command: impl Command)
pub fn queue_silenced(&mut self, command: impl Command)
Pushes a generic Command to the queue like Commands::queue_handled, but instead silently ignores any errors.
Sourcepub fn insert_batch<I, B>(&mut self, batch: I)where
I: IntoIterator<Item = (Entity, B)> + Send + Sync + 'static,
B: Bundle,
<B as DynamicBundle>::Effect: NoBundleEffect,
pub fn insert_batch<I, B>(&mut self, batch: I)where
I: IntoIterator<Item = (Entity, B)> + Send + Sync + 'static,
B: Bundle,
<B as DynamicBundle>::Effect: NoBundleEffect,
Adds a series of Bundles to each Entity they are paired with,
based on a batch of (Entity, Bundle) pairs.
A batch can be any type that implements IntoIterator
and contains (Entity, Bundle) tuples,
such as a Vec<(Entity, Bundle)>
or an array [(Entity, Bundle); N].
This will overwrite any pre-existing components shared by the Bundle type.
Use Commands::insert_batch_if_new to keep the pre-existing components instead.
This method is equivalent to iterating the batch
and calling insert for each pair,
but is faster by caching data that is shared between entities.
§Fallible
This command will fail if any of the given entities do not exist.
It will internally return a TryInsertBatchError,
which will be handled by the fallback error handler.
Sourcepub fn insert_batch_if_new<I, B>(&mut self, batch: I)where
I: IntoIterator<Item = (Entity, B)> + Send + Sync + 'static,
B: Bundle,
<B as DynamicBundle>::Effect: NoBundleEffect,
pub fn insert_batch_if_new<I, B>(&mut self, batch: I)where
I: IntoIterator<Item = (Entity, B)> + Send + Sync + 'static,
B: Bundle,
<B as DynamicBundle>::Effect: NoBundleEffect,
Adds a series of Bundles to each Entity they are paired with,
based on a batch of (Entity, Bundle) pairs.
A batch can be any type that implements IntoIterator
and contains (Entity, Bundle) tuples,
such as a Vec<(Entity, Bundle)>
or an array [(Entity, Bundle); N].
This will keep any pre-existing components shared by the Bundle type
and discard the new values.
Use Commands::insert_batch to overwrite the pre-existing components instead.
This method is equivalent to iterating the batch
and calling insert_if_new for each pair,
but is faster by caching data that is shared between entities.
§Fallible
This command will fail if any of the given entities do not exist.
It will internally return a TryInsertBatchError,
which will be handled by the fallback error handler.
Sourcepub fn try_insert_batch<I, B>(&mut self, batch: I)where
I: IntoIterator<Item = (Entity, B)> + Send + Sync + 'static,
B: Bundle,
<B as DynamicBundle>::Effect: NoBundleEffect,
pub fn try_insert_batch<I, B>(&mut self, batch: I)where
I: IntoIterator<Item = (Entity, B)> + Send + Sync + 'static,
B: Bundle,
<B as DynamicBundle>::Effect: NoBundleEffect,
Adds a series of Bundles to each Entity they are paired with,
based on a batch of (Entity, Bundle) pairs.
A batch can be any type that implements IntoIterator
and contains (Entity, Bundle) tuples,
such as a Vec<(Entity, Bundle)>
or an array [(Entity, Bundle); N].
This will overwrite any pre-existing components shared by the Bundle type.
Use Commands::try_insert_batch_if_new to keep the pre-existing components instead.
This method is equivalent to iterating the batch
and calling insert for each pair,
but is faster by caching data that is shared between entities.
§Fallible
This command will fail if any of the given entities do not exist.
It will internally return a TryInsertBatchError,
which will be handled by logging the error at the warn level.
Examples found in repository?
517pub fn extract_colored_mesh2d(
518 mut commands: Commands,
519 mut previous_len: Local<usize>,
520 // When extracting, you must use `Extract` to mark the `SystemParam`s
521 // which should be taken from the main world.
522 query: Extract<
523 Query<
524 (
525 Entity,
526 RenderEntity,
527 &ViewVisibility,
528 &GlobalTransform,
529 &Mesh2d,
530 ),
531 With<ColoredMesh2d>,
532 >,
533 >,
534 mut render_mesh_instances: ResMut<RenderColoredMesh2dInstances>,
535) {
536 let mut values = Vec::with_capacity(*previous_len);
537 for (entity, render_entity, view_visibility, transform, handle) in &query {
538 if !view_visibility.get() {
539 continue;
540 }
541
542 let transforms = Mesh2dTransforms {
543 world_from_local: transform.affine().into(),
544 flags: MeshFlags::empty().bits(),
545 };
546
547 values.push((render_entity, ColoredMesh2d));
548 render_mesh_instances.insert(
549 entity.into(),
550 RenderMesh2dInstance {
551 mesh_asset_id: handle.0.id(),
552 transforms,
553 // This is unused here.
554 material_bindings_index: MaterialBindingId::default(),
555 automatic_batching: false,
556 tag: 0,
557 },
558 );
559 }
560 *previous_len = values.len();
561 commands.try_insert_batch(values);
562}Sourcepub fn try_insert_batch_if_new<I, B>(&mut self, batch: I)where
I: IntoIterator<Item = (Entity, B)> + Send + Sync + 'static,
B: Bundle,
<B as DynamicBundle>::Effect: NoBundleEffect,
pub fn try_insert_batch_if_new<I, B>(&mut self, batch: I)where
I: IntoIterator<Item = (Entity, B)> + Send + Sync + 'static,
B: Bundle,
<B as DynamicBundle>::Effect: NoBundleEffect,
Adds a series of Bundles to each Entity they are paired with,
based on a batch of (Entity, Bundle) pairs.
A batch can be any type that implements IntoIterator
and contains (Entity, Bundle) tuples,
such as a Vec<(Entity, Bundle)>
or an array [(Entity, Bundle); N].
This will keep any pre-existing components shared by the Bundle type
and discard the new values.
Use Commands::try_insert_batch to overwrite the pre-existing components instead.
This method is equivalent to iterating the batch
and calling insert_if_new for each pair,
but is faster by caching data that is shared between entities.
§Fallible
This command will fail if any of the given entities do not exist.
It will internally return a TryInsertBatchError,
which will be handled by logging the error at the warn level.
Sourcepub fn init_resource<R>(&mut self)
pub fn init_resource<R>(&mut self)
Inserts a Resource into the World with an inferred value.
The inferred value is determined by the FromWorld trait of the resource.
Note that any resource with the Default trait automatically implements FromWorld,
and those default values will be used.
If the resource already exists when the command is applied, nothing happens.
§Example
#[derive(Resource, Default)]
struct Scoreboard {
current_score: u32,
high_score: u32,
}
fn initialize_scoreboard(mut commands: Commands) {
commands.init_resource::<Scoreboard>();
}Examples found in repository?
More examples
58fn setup(
59 mut commands: Commands,
60 mut meshes: ResMut<Assets<Mesh>>,
61 mut materials: ResMut<Assets<StandardMaterial>>,
62) {
63 // circular base
64 commands.spawn((
65 Mesh3d(meshes.add(Circle::new(4.0))),
66 MeshMaterial3d(materials.add(Color::WHITE)),
67 Transform::from_rotation(Quat::from_rotation_x(-std::f32::consts::FRAC_PI_2)),
68 ));
69 // cube
70 commands.spawn((
71 Mesh3d(meshes.add(Cuboid::new(1.0, 1.0, 1.0))),
72 MeshMaterial3d(materials.add(Color::srgb_u8(124, 144, 255))),
73 Transform::from_xyz(0.0, 0.5, 0.0),
74 ));
75 // light
76 commands.spawn((
77 PointLight {
78 shadow_maps_enabled: true,
79 ..default()
80 },
81 Transform::from_xyz(4.0, 8.0, 4.0),
82 ));
83 // camera
84 commands.spawn((
85 Camera3d::default(),
86 Transform::from_xyz(-2.5, 4.5, 9.0).looking_at(Vec3::ZERO, Vec3::Y),
87 ));
88
89 commands.init_resource::<LogDiagnosticsFilters>();
90 commands.init_resource::<LogDiagnosticsStatus>();
91
92 commands.spawn((
93 LogDiagnosticsCommands,
94 Node {
95 top: px(5),
96 left: px(5),
97 flex_direction: FlexDirection::Column,
98 ..default()
99 },
100 ));
101}Sourcepub fn insert_resource<R>(&mut self, resource: R)where
R: Resource,
pub fn insert_resource<R>(&mut self, resource: R)where
R: Resource,
Inserts a Resource into the World with a specific value.
This will overwrite any previous value of the same resource type.
§Example
#[derive(Resource)]
struct Scoreboard {
current_score: u32,
high_score: u32,
}
fn system(mut commands: Commands) {
commands.insert_resource(Scoreboard {
current_score: 0,
high_score: 0,
});
}Examples found in repository?
More examples
89fn setup_channel(mut commands: Commands) {
90 let (sender, receiver) = crossbeam_channel::unbounded();
91 commands.insert_resource(CubeChannel { sender, receiver });
92}
93
94/// A channel for communicating between async tasks and the main thread.
95#[derive(Resource)]
96struct CubeChannel {
97 sender: Sender<CubeFinished>,
98 receiver: Receiver<CubeFinished>,
99}
100
101/// Represents the completion of a cube task, containing the cube's transform
102#[derive(Debug)]
103struct CubeFinished {
104 transform: Transform,
105}
106
107/// Resource holding the mesh handle for the box (used for spawning cubes)
108#[derive(Resource, Deref)]
109struct BoxMeshHandle(Handle<Mesh>);
110
111/// Resource holding the material handle for the box (used for spawning cubes)
112#[derive(Resource, Deref)]
113struct BoxMaterialHandle(Handle<StandardMaterial>);
114
115/// Sets up the shared mesh and material for the cubes.
116fn setup_assets(
117 mut commands: Commands,
118 mut meshes: ResMut<Assets<Mesh>>,
119 mut materials: ResMut<Assets<StandardMaterial>>,
120) {
121 // Create and store a cube mesh
122 let box_mesh_handle = meshes.add(Cuboid::new(0.4, 0.4, 0.4));
123 commands.insert_resource(BoxMeshHandle(box_mesh_handle));
124
125 // Create and store a red material
126 let box_material_handle = materials.add(Color::srgb(1.0, 0.2, 0.3));
127 commands.insert_resource(BoxMaterialHandle(box_material_handle));
128}- examples/ecs/change_detection.rs
- examples/shader_advanced/specialized_mesh_pipeline.rs
- examples/2d/mesh2d_manual.rs
- examples/async_tasks/async_compute.rs
- examples/3d/mirror.rs
- examples/asset/processing/asset_processing.rs
- examples/2d/sprite_tile.rs
- examples/audio/soundtrack.rs
- examples/showcase/desk_toy.rs
- examples/async_tasks/external_source_external_thread.rs
- examples/ecs/ecs_guide.rs
- examples/showcase/loading_screen.rs
- examples/window/window_settings.rs
- examples/2d/dynamic_mip_generation.rs
- examples/shader/compute_shader_game_of_life.rs
- examples/shader_advanced/compute_mesh.rs
- examples/showcase/game_menu.rs
- examples/shader_advanced/manual_material.rs
- examples/remote/server.rs
- examples/ui/text/font_atlas_debug.rs
- examples/asset/multi_asset_sync.rs
- examples/testbed/3d.rs
- examples/gltf/gltf_extension_animation_graph.rs
- examples/state/custom_transitions.rs
- examples/state/states.rs
- examples/shader/gpu_component_array_buffer.rs
- examples/3d/skybox.rs
- examples/shader/storage_buffer.rs
- examples/state/sub_states.rs
- examples/movement/smooth_follow.rs
- examples/2d/tilemap_chunk.rs
- examples/animation/animated_mesh_control.rs
- examples/asset/generated_assets.rs
- examples/showcase/contributors.rs
- examples/testbed/2d.rs
- examples/gizmos/axes.rs
- examples/3d/motion_blur.rs
- examples/3d/atmosphere.rs
- examples/animation/animated_mesh_events.rs
- examples/3d/rect_light.rs
- examples/math/cubic_splines.rs
- examples/animation/animation_graph.rs
- examples/2d/cpu_draw.rs
- examples/shader_advanced/mesh_shader_intro.rs
- examples/shader_advanced/custom_post_processing.rs
- examples/transforms/align.rs
- examples/math/random_sampling.rs
- examples/shader_advanced/deferred_raymarch.rs
- examples/state/computed_states.rs
- examples/animation/animation_masks.rs
- examples/3d/solari.rs
- tests/3d/test_meshlet.rs
- examples/showcase/alien_cake_addict.rs
- examples/asset/asset_saving.rs
- examples/shader/gpu_readback.rs
- examples/3d/auto_exposure.rs
- examples/stress_tests/bevymark_3d.rs
- examples/stress_tests/bevymark.rs
- examples/3d/solari_reflections.rs
- examples/ui/scroll_and_overflow/drag_to_scroll.rs
- examples/showcase/breakout.rs
- examples/stress_tests/many_foxes.rs
- examples/testbed/ui.rs
- examples/3d/lighting.rs
Sourcepub fn insert_resource_if_neq<R>(&mut self, resource: R)
pub fn insert_resource_if_neq<R>(&mut self, resource: R)
Sourcepub fn remove_resource<R>(&mut self)where
R: Resource,
pub fn remove_resource<R>(&mut self)where
R: Resource,
Removes a Resource from the World.
§Example
#[derive(Resource)]
struct Scoreboard {
current_score: u32,
high_score: u32,
}
fn system(mut commands: Commands) {
commands.remove_resource::<Scoreboard>();
}Examples found in repository?
More examples
Sourcepub fn run_system(&mut self, id: impl Into<SystemId> + Send)
pub fn run_system(&mut self, id: impl Into<SystemId> + Send)
Runs the system corresponding to the given SystemId.
Before running a system, it must first be registered via
Commands::register_system or World::register_system.
The system is run in an exclusive and single-threaded way. Running slow systems can become a bottleneck.
There is no way to get the output of a system when run as a command, because the
execution of the system happens later. To get the output of a system, use
World::run_system or World::run_system_with instead of running the system as a command.
§Fallible
This command will fail if the given SystemId
does not correspond to a System.
It will internally return a RegisteredSystemError,
which will be handled by logging the error at the warn level.
Examples found in repository?
More examples
98fn level_selection(
99 mut commands: Commands,
100 keyboard: Res<ButtonInput<KeyCode>>,
101 level_data: Res<LevelData>,
102 loading_state: Res<LoadingState>,
103) {
104 // Only trigger a load if the current level is fully loaded.
105 if let LoadingState::LevelReady = loading_state.as_ref() {
106 if keyboard.just_pressed(KeyCode::Digit1) {
107 commands.run_system(level_data.unload_level_id);
108 commands.run_system(level_data.level_1_id);
109 } else if keyboard.just_pressed(KeyCode::Digit2) {
110 commands.run_system(level_data.unload_level_id);
111 commands.run_system(level_data.level_2_id);
112 }
113 }
114}Sourcepub fn run_system_with<I>(
&mut self,
id: impl Into<SystemId<I>> + Send,
input: <I as SystemInput>::Inner<'static>,
)
pub fn run_system_with<I>( &mut self, id: impl Into<SystemId<I>> + Send, input: <I as SystemInput>::Inner<'static>, )
Runs the system corresponding to the given SystemId with input.
Before running a system, it must first be registered via
Commands::register_system or World::register_system.
The system is run in an exclusive and single-threaded way. Running slow systems can become a bottleneck.
There is no way to get the output of a system when run as a command, because the
execution of the system happens later. To get the output of a system, use
World::run_system or World::run_system_with instead of running the system as a command.
§Fallible
This command will fail if the given SystemId
does not correspond to a System.
It will internally return a RegisteredSystemError,
which will be handled by logging the error at the warn level.
Sourcepub fn register_system<I, O, M>(
&mut self,
system: impl IntoSystem<I, O, M> + 'static,
) -> SystemId<I, O>
pub fn register_system<I, O, M>( &mut self, system: impl IntoSystem<I, O, M> + 'static, ) -> SystemId<I, O>
Registers a system and returns its SystemId so it can later be called by
Commands::run_system or World::run_system.
This is different from adding systems to a Schedule,
because the SystemId that is returned can be used anywhere in the World to run the associated system.
Using a Schedule is still preferred for most cases
due to its better performance and ability to run non-conflicting systems simultaneously.
§Note
If the same system is registered more than once,
each registration will be considered a different system,
and they will each be given their own SystemId.
If you want to avoid registering the same system multiple times,
consider using Commands::run_system_cached or storing the SystemId
in a Local.
§Example
#[derive(Resource)]
struct Counter(i32);
fn register_system(
mut commands: Commands,
mut local_system: Local<Option<SystemId>>,
) {
if let Some(system) = *local_system {
commands.run_system(system);
} else {
*local_system = Some(commands.register_system(increment_counter));
}
}
fn increment_counter(mut value: ResMut<Counter>) {
value.0 += 1;
}
Examples found in repository?
More examples
72fn setup(mut commands: Commands) {
73 let level_data = LevelData {
74 unload_level_id: commands.register_system(unload_current_level),
75 level_1_id: commands.register_system(load_level_1),
76 level_2_id: commands.register_system(load_level_2),
77 };
78 commands.insert_resource(level_data);
79
80 // Spawns the UI that will show the user prompts.
81 let text_style = TextFont {
82 font_size: FontSize::Px(42.0),
83 ..default()
84 };
85 commands
86 .spawn((
87 Node {
88 justify_self: JustifySelf::Center,
89 align_self: AlignSelf::FlexEnd,
90 ..default()
91 },
92 BackgroundColor(Color::NONE),
93 ))
94 .with_child((Text::new("Press 1 or 2 to load a new scene."), text_style));
95}21fn setup_callbacks(mut commands: Commands) {
22 let trivial_callback = Callback {
23 system_id: commands.register_system(|| {
24 println!("This is the trivial callback system");
25 }),
26 };
27
28 let ordinary_system_callback = Callback {
29 system_id: commands.register_system(|query: Query<&Callback>| {
30 let n_callbacks = query.iter().len();
31 println!("This is the ordinary callback system. There are currently {n_callbacks} callbacks in the world.");
32 }),
33 };
34
35 let exclusive_callback = Callback {
36 system_id: commands.register_system(|world: &mut World| {
37 let n_entities = world.entities().len();
38 println!("This is the exclusive callback system. There are currently {n_entities} entities in the world.");
39 }),
40 };
41
42 commands.spawn(trivial_callback);
43 commands.spawn(ordinary_system_callback);
44 commands.spawn(exclusive_callback);
45
46 // It is also possible to register systems that are already boxed.
47
48 let boxed_trivial_system = Box::new(IntoSystem::into_system(|| {
49 println!("This is the boxed trivial callback system");
50 }));
51
52 let boxed_trivial_callback = Callback {
53 system_id: commands.register_boxed_system(boxed_trivial_system),
54 };
55
56 let boxed_ordinary_system = Box::new(IntoSystem::into_system(|query: Query<&Callback>| {
57 let n_callbacks = query.iter().len();
58 println!("This is the boxed ordinary callback system. There are currently {n_callbacks} callbacks in the world.");
59 }));
60
61 let boxed_ordinary_system_callback = Callback {
62 system_id: commands.register_boxed_system(boxed_ordinary_system),
63 };
64
65 let boxed_exclusive_system = Box::new(IntoSystem::into_system(|world: &mut World| {
66 let n_entities = world.entities().len();
67 println!("This is the boxed exclusive callback system. There are currently {n_entities} entities in the world.");
68 }));
69
70 let boxed_exclusive_callback = Callback {
71 system_id: commands.register_boxed_system(boxed_exclusive_system),
72 };
73
74 commands.spawn(boxed_trivial_callback);
75 commands.spawn(boxed_ordinary_system_callback);
76 commands.spawn(boxed_exclusive_callback);
77}Sourcepub fn register_boxed_system<I, O>(
&mut self,
system: Box<dyn System<Out = O, In = I>>,
) -> SystemId<I, O>
pub fn register_boxed_system<I, O>( &mut self, system: Box<dyn System<Out = O, In = I>>, ) -> SystemId<I, O>
Registers a BoxedSystem and returns its SystemId so it can later be called by
Commands::run_system or World::run_system.
This is different from adding systems to a Schedule,
because the SystemId that is returned can be used anywhere in the World to run the associated system.
Using a Schedule is still preferred for most cases
due to its better performance and ability to run non-conflicting systems simultaneously.
§Note
If the same system is registered more than once,
each registration will be considered a different system,
and they will each be given their own SystemId.
If you want to avoid registering the same system multiple times,
consider using Commands::run_system_cached or storing the SystemId
in a Local.
§Example
#[derive(Resource)]
struct Counter(i32);
fn register_system(
mut commands: Commands,
mut local_system: Local<Option<SystemId>>,
) {
if let Some(system) = *local_system {
commands.run_system(system);
} else {
let boxed_system = Box::new(IntoSystem::into_system(increment_counter));
*local_system = Some(commands.register_boxed_system(boxed_system));
}
}
fn increment_counter(mut value: ResMut<Counter>) {
value.0 += 1;
}
§See also
register_systemto register a system that has not been boxed.
Examples found in repository?
21fn setup_callbacks(mut commands: Commands) {
22 let trivial_callback = Callback {
23 system_id: commands.register_system(|| {
24 println!("This is the trivial callback system");
25 }),
26 };
27
28 let ordinary_system_callback = Callback {
29 system_id: commands.register_system(|query: Query<&Callback>| {
30 let n_callbacks = query.iter().len();
31 println!("This is the ordinary callback system. There are currently {n_callbacks} callbacks in the world.");
32 }),
33 };
34
35 let exclusive_callback = Callback {
36 system_id: commands.register_system(|world: &mut World| {
37 let n_entities = world.entities().len();
38 println!("This is the exclusive callback system. There are currently {n_entities} entities in the world.");
39 }),
40 };
41
42 commands.spawn(trivial_callback);
43 commands.spawn(ordinary_system_callback);
44 commands.spawn(exclusive_callback);
45
46 // It is also possible to register systems that are already boxed.
47
48 let boxed_trivial_system = Box::new(IntoSystem::into_system(|| {
49 println!("This is the boxed trivial callback system");
50 }));
51
52 let boxed_trivial_callback = Callback {
53 system_id: commands.register_boxed_system(boxed_trivial_system),
54 };
55
56 let boxed_ordinary_system = Box::new(IntoSystem::into_system(|query: Query<&Callback>| {
57 let n_callbacks = query.iter().len();
58 println!("This is the boxed ordinary callback system. There are currently {n_callbacks} callbacks in the world.");
59 }));
60
61 let boxed_ordinary_system_callback = Callback {
62 system_id: commands.register_boxed_system(boxed_ordinary_system),
63 };
64
65 let boxed_exclusive_system = Box::new(IntoSystem::into_system(|world: &mut World| {
66 let n_entities = world.entities().len();
67 println!("This is the boxed exclusive callback system. There are currently {n_entities} entities in the world.");
68 }));
69
70 let boxed_exclusive_callback = Callback {
71 system_id: commands.register_boxed_system(boxed_exclusive_system),
72 };
73
74 commands.spawn(boxed_trivial_callback);
75 commands.spawn(boxed_ordinary_system_callback);
76 commands.spawn(boxed_exclusive_callback);
77}Sourcepub fn unregister_system<I, O>(&mut self, system_id: SystemId<I, O>)
pub fn unregister_system<I, O>(&mut self, system_id: SystemId<I, O>)
Removes a system previously registered with Commands::register_system
or World::register_system.
After removing a system, the SystemId becomes invalid
and attempting to use it afterwards will result in an error.
Re-adding the removed system will register it with a new SystemId.
§Fallible
This command will fail if the given SystemId
does not correspond to a System.
It will internally return a RegisteredSystemError,
which will be handled by logging the error at the warn level.
Sourcepub fn unregister_system_cached<I, O, M, S>(&mut self, system: S)where
I: SystemInput + Send + 'static,
O: 'static,
M: 'static,
S: IntoSystem<I, O, M> + Send + 'static,
pub fn unregister_system_cached<I, O, M, S>(&mut self, system: S)where
I: SystemInput + Send + 'static,
O: 'static,
M: 'static,
S: IntoSystem<I, O, M> + Send + 'static,
Removes a system previously registered with one of the following:
§Fallible
This command will fail if the given system
is not currently cached in a CachedSystemId resource.
It will internally return a RegisteredSystemError,
which will be handled by logging the error at the warn level.
Sourcepub fn run_system_cached<M, S>(&mut self, system: S)
pub fn run_system_cached<M, S>(&mut self, system: S)
Runs a cached system, registering it if necessary.
Unlike Commands::run_system, this method does not require manual registration.
The first time this method is called for a particular system,
it will register the system and store its SystemId in a
CachedSystemId resource for later.
If you would rather manage the SystemId yourself,
or register multiple copies of the same system,
use Commands::register_system instead.
§Limitations
This method only accepts ZST (zero-sized) systems to guarantee that any two systems of the same type must be equal. This means that closures that capture the environment, and function pointers, are not accepted.
If you want to access values from the environment within a system,
consider passing them in as inputs via Commands::run_system_cached_with.
If that’s not an option, consider Commands::register_system instead.
Sourcepub fn run_system_cached_with<I, M, S>(
&mut self,
system: S,
input: <I as SystemInput>::Inner<'static>,
)where
I: SystemInput + Send + 'static,
<I as SystemInput>::Inner<'static>: Send,
M: 'static,
S: IntoSystem<I, (), M> + Send + 'static,
pub fn run_system_cached_with<I, M, S>(
&mut self,
system: S,
input: <I as SystemInput>::Inner<'static>,
)where
I: SystemInput + Send + 'static,
<I as SystemInput>::Inner<'static>: Send,
M: 'static,
S: IntoSystem<I, (), M> + Send + 'static,
Runs a cached system with an input, registering it if necessary.
Unlike Commands::run_system_with, this method does not require manual registration.
To use the supplied input, the system should have a SystemInput as the first parameter.
The first time this method is called for a particular system,
it will register the system and store its SystemId in a
CachedSystemId resource for later.
If you would rather manage the SystemId yourself,
or register multiple copies of the same system,
use Commands::register_system instead.
§Limitations
This method only accepts ZST (zero-sized) systems to guarantee that any two systems of the same type must be equal. This means that closures that capture the environment, and function pointers, are not accepted.
If you want to access values from the environment within a system, consider passing them in as inputs.
If that’s not an option, consider Commands::register_system instead.
Sourcepub fn trigger<'a>(&mut self, event: impl Event : Default>)
pub fn trigger<'a>(&mut self, event: impl Event : Default>)
Examples found in repository?
194fn on_drag_start(drag_start: On<PointerDragStart>, mut commands: Commands) {
195 commands.trigger(TryPlot {
196 entity: drag_start.entity,
197 location: drag_start.pointer.location(),
198 });
199}
200
201fn on_drag(drag: On<PointerDrag>, mut commands: Commands) {
202 commands.trigger(TryPlot {
203 entity: drag.entity,
204 location: drag.pointer.location(),
205 });
206}More examples
66fn setup(mut commands: Commands) {
67 commands.spawn(Camera2d);
68
69 commands.spawn_scene(bsn! {
70 @background()
71 on(|press: On<PointerPress>, query: Query<(), With<ContextMenu>>, mut commands: Commands| {
72 debug!("click: {}", press.pointer.position);
73
74 if query.is_empty() {
75 // Open the context menu at the pointer location if one does not exist
76 commands.trigger(OpenContextMenu {
77 pos: press.pointer.position,
78 });
79 } else {
80 // Close the context menu if it exists
81 commands.trigger(CloseContextMenus);
82 }
83 })
84 });
85}
86
87fn on_trigger_close_menus(
88 _event: On<CloseContextMenus>,
89 mut commands: Commands,
90 menus: Query<Entity, With<ContextMenu>>,
91) {
92 for e in menus.iter() {
93 commands.entity(e).despawn();
94 }
95}
96
97fn on_trigger_menu(event: On<OpenContextMenu>, mut commands: Commands) {
98 commands.trigger(CloseContextMenus);
99
100 let pos = event.pos;
101
102 debug!("open context menu at: {pos}");
103
104 commands.spawn_scene(bsn! {
105 #ContextMenu
106 ContextMenu
107 Node {
108 position_type: PositionType::Absolute,
109 left: px(pos.x),
110 top: px(pos.y),
111 flex_direction: FlexDirection::Column,
112 border_radius: BorderRadius::all(px(4)),
113 }
114 BorderColor::all(Color::BLACK)
115 BackgroundColor(Color::linear_rgb(0.1, 0.1, 0.1))
116 ListBox
117 Children [
118 @context_item("fuchsia", basic::FUCHSIA)
119 --
120 @context_item("gray", basic::GRAY)
121 --
122 @context_item("maroon", basic::MAROON)
123 --
124 @context_item("purple", basic::PURPLE)
125 --
126 @context_item("teal", basic::TEAL)
127 ]
128 on(|event: On<ValueChange<Entity>>,
129 menu_items: Query<&ContextMenuItem, With<ListItem>>,
130 mut clear_col: ResMut<ClearColor>,
131 mut commands: Commands| {
132 let Ok(selected) = menu_items.get(event.value) else {
133 return;
134 };
135 clear_col.0 = selected.0.into();
136 commands.trigger(CloseContextMenus);
137
138 // We do not set the `Selected` state of any of the items because the menu
139 // will be despawned.
140 })
141 });
142}27fn send_scroll_events(
28 mut mouse_wheel_reader: MessageReader<MouseWheel>,
29 hover_map: Res<HoverMap>,
30 keyboard_input: Res<ButtonInput<KeyCode>>,
31 mut commands: Commands,
32) {
33 for mouse_wheel in mouse_wheel_reader.read() {
34 let mut delta = -Vec2::new(mouse_wheel.x, mouse_wheel.y);
35
36 if mouse_wheel.unit == MouseScrollUnit::Line {
37 delta *= LINE_HEIGHT;
38 }
39
40 if keyboard_input.any_pressed([KeyCode::ControlLeft, KeyCode::ControlRight]) {
41 std::mem::swap(&mut delta.x, &mut delta.y);
42 }
43
44 for pointer_map in hover_map.values() {
45 for entity in pointer_map.keys().copied() {
46 commands.trigger(Scroll { entity, delta });
47 }
48 }
49 }
50}459fn interact_with_focused_button(
460 action_state: Res<ActionState>,
461 input_focus: Res<InputFocus>,
462 mut commands: Commands,
463) {
464 if action_state
465 .pressed_actions
466 .contains(&DirectionalNavigationAction::Select)
467 && let Some(focused_entity) = input_focus.get()
468 {
469 commands.trigger(PointerClick {
470 entity: focused_entity,
471 pointer: Pointer::new(
472 PointerId::Mouse,
473 Location {
474 target: NormalizedRenderTarget::None {
475 width: 0,
476 height: 0,
477 },
478 position: Vec2::ZERO,
479 },
480 ),
481 button: PointerButton::Primary,
482 hit: HitData {
483 camera: Entity::PLACEHOLDER,
484 depth: 0.0,
485 position: None,
486 normal: None,
487 extra: None,
488 },
489 count: 1,
490 duration: Duration::from_secs_f32(0.1),
491 });
492 }
493}802fn interact_with_focused_button(
803 action_state: Res<ActionState>,
804 input_focus: Res<InputFocus>,
805 mut commands: Commands,
806) {
807 if action_state
808 .pressed_actions
809 .contains(&DirectionalNavigationAction::Select)
810 && let Some(focused_entity) = input_focus.get()
811 {
812 commands.trigger(PointerClick {
813 entity: focused_entity,
814 pointer: Pointer::new(
815 PointerId::Mouse,
816 Location {
817 target: NormalizedRenderTarget::None {
818 width: 0,
819 height: 0,
820 },
821 position: Vec2::ZERO,
822 },
823 ),
824 button: PointerButton::Primary,
825 hit: HitData {
826 camera: Entity::PLACEHOLDER,
827 depth: 0.0,
828 position: None,
829 normal: None,
830 extra: None,
831 },
832 count: 1,
833 duration: Duration::from_secs_f32(0.1),
834 });
835 }
836}Sourcepub fn trigger_with<E>(
&mut self,
event: E,
trigger: <E as Event>::Trigger<'static>,
)
pub fn trigger_with<E>( &mut self, event: E, trigger: <E as Event>::Trigger<'static>, )
Sourcepub fn add_observer<M>(
&mut self,
observer: impl IntoObserver<M>,
) -> EntityCommands<'_>
pub fn add_observer<M>( &mut self, observer: impl IntoObserver<M>, ) -> EntityCommands<'_>
Spawns an Observer and returns the EntityCommands associated
with the entity that stores the observer.
observer can be any system whose first parameter is On.
Calling observe on the returned
EntityCommands will observe the observer itself, which you very
likely do not want.
§Panics
Panics if the given system is an exclusive system.
Sourcepub fn write_message<M>(&mut self, message: M) -> &mut Commands<'w, 's>where
M: Message,
pub fn write_message<M>(&mut self, message: M) -> &mut Commands<'w, 's>where
M: Message,
Writes an arbitrary Message.
This is a convenience method for writing messages
without requiring a MessageWriter.
§Performance
Since this is a command, exclusive world access is used, which means that it will not profit from system-level parallelism on supported platforms.
If these messages are performance-critical or very frequently sent,
consider using a MessageWriter instead.
Examples found in repository?
More examples
138fn setup(
139 mut commands: Commands,
140 asset_server: Res<AssetServer>,
141 app_status: Res<AppStatus>,
142 render_device: Res<RenderDevice>,
143 render_adapter: Res<RenderAdapter>,
144 mut meshes: ResMut<Assets<Mesh>>,
145 mut materials: ResMut<Assets<ExtendedMaterial<StandardMaterial, CustomDecalExtension>>>,
146) {
147 // Error out if clustered decals aren't supported on the current platform.
148 if !decal::clustered::clustered_decals_are_usable(&render_device, &render_adapter) {
149 error!("Clustered decals aren't usable on this platform.");
150 commands.write_message(AppExit::error());
151 }
152
153 spawn_cube(&mut commands, &mut meshes, &mut materials);
154 spawn_camera(&mut commands);
155 spawn_light(&mut commands);
156 spawn_decals(&mut commands, &asset_server);
157 spawn_buttons(&mut commands);
158 spawn_help_text(&mut commands, &app_status);
159}131fn setup(
132 mut commands: Commands,
133 asset_server: Res<AssetServer>,
134 app_status: Res<AppStatus>,
135 render_device: Res<RenderDevice>,
136 render_adapter: Res<RenderAdapter>,
137 mut meshes: ResMut<Assets<Mesh>>,
138 mut materials: ResMut<Assets<StandardMaterial>>,
139) {
140 // Error out if clustered decals (and so light textures) aren't supported on the current platform.
141 if !decal::clustered::clustered_decals_are_usable(&render_device, &render_adapter) {
142 error!("Light textures aren't usable on this platform.");
143 commands.write_message(AppExit::error());
144 }
145
146 spawn_cubes(&mut commands, &mut meshes, &mut materials);
147 spawn_camera(&mut commands);
148 spawn_light(&mut commands, &asset_server);
149 spawn_buttons(&mut commands);
150 spawn_help_text(&mut commands, &app_status);
151 spawn_light_textures(&mut commands, &asset_server, &mut meshes, &mut materials);
152}Sourcepub fn run_schedule(&mut self, label: impl ScheduleLabel)
pub fn run_schedule(&mut self, label: impl ScheduleLabel)
Runs the schedule corresponding to the given ScheduleLabel.
Calls World::try_run_schedule.
§Fallible
This command will fail if the given ScheduleLabel
does not correspond to a Schedule.
It will internally return a TryRunScheduleError,
which will be handled by logging the error at the warn level.
§Example
#[derive(ScheduleLabel, Hash, Debug, PartialEq, Eq, Clone, Copy)]
struct FooSchedule;
commands.run_schedule(FooSchedule);Trait Implementations§
Source§impl<'w, 's> CommandsSceneExt for Commands<'w, 's>
impl<'w, 's> CommandsSceneExt for Commands<'w, 's>
Source§fn spawn_scene<S>(&mut self, scene: S) -> EntityCommands<'_>where
S: Scene,
fn spawn_scene<S>(&mut self, scene: S) -> EntityCommands<'_>where
S: Scene,
Scene as soon as Commands are applied. This will resolve the Scene (using Scene::resolve). If that fails (for example, if there are dependencies that have not been
loaded yet), it will log a SpawnSceneError as an error. If resolving the Scene is successful, the scene will be spawned. Read moreSource§fn queue_spawn_scene<S>(&mut self, scene: S) -> EntityCommands<'_>where
S: Scene,
fn queue_spawn_scene<S>(&mut self, scene: S) -> EntityCommands<'_>where
S: Scene,
scene to be spawned. This will evaluate the scene’s dependencies (via Scene::register_dependencies) and queue it to be resolved and spawned
after all of the dependencies have been loaded. If a SpawnSceneError occurs, it will be logged as an error. Read moreSource§fn spawn_scene_list<L>(&mut self, scenes: L)where
L: SceneList,
fn spawn_scene_list<L>(&mut self, scenes: L)where
L: SceneList,
SceneList as soon as Commands are applied. This will resolve the scene list (using SceneList::resolve_list). If that fails (for example, if there are dependencies that have not been
loaded yet), it will log a SpawnSceneError as an error. If resolving the Scene is successful, the scene list will be spawned. Read moreSource§fn queue_spawn_scene_list<L>(&mut self, scenes: L)where
L: SceneList,
fn queue_spawn_scene_list<L>(&mut self, scenes: L)where
L: SceneList,
scene_list to be spawned. This will evaluate the scene_list’s dependencies (via Scene::register_dependencies) and queue it to be resolved
and spawned after all of the dependencies have been loaded. If a SpawnSceneError occurs, it will be logged as an error. Read moreSource§impl CommandsStatesExt for Commands<'_, '_>
impl CommandsStatesExt for Commands<'_, '_>
Source§fn set_state<S>(&mut self, state: S)where
S: FreelyMutableState,
fn set_state<S>(&mut self, state: S)where
S: FreelyMutableState,
Source§fn set_state_if_different<S>(&mut self, state: S)where
S: FreelyMutableState,
fn set_state_if_different<S>(&mut self, state: S)where
S: FreelyMutableState,
Source§impl<'w, 's> DelayedCommandsExt<'w> for Commands<'w, 's>
impl<'w, 's> DelayedCommandsExt<'w> for Commands<'w, 's>
Source§fn delayed(&mut self) -> DelayedCommands<'w, '_>
fn delayed(&mut self) -> DelayedCommands<'w, '_>
DelayedCommands instance that can be used to queue
commands to be submitted at a later point in time. Read moreimpl<'w, 's> ReadOnlySystemParam for Commands<'w, 's>where
Deferred<'s, CommandQueue>: ReadOnlySystemParam,
&'w Entities: ReadOnlySystemParam,
&'w EntityAllocator: ReadOnlySystemParam,
impl Send for Commands<'_, '_>
impl Sync for Commands<'_, '_>
Source§impl SystemParam for Commands<'_, '_>
impl SystemParam for Commands<'_, '_>
Source§type Item<'w, 's> = Commands<'w, 's>
type Item<'w, 's> = Commands<'w, 's>
Self, instantiated with new lifetimes. Read moreSource§fn init_state(world: &mut World) -> <Commands<'_, '_> as SystemParam>::State
fn init_state(world: &mut World) -> <Commands<'_, '_> as SystemParam>::State
State.Source§fn init_access(
state: &<Commands<'_, '_> as SystemParam>::State,
system_meta: &mut SystemMeta,
system_access: &mut SystemAccess,
world: &mut World,
)
fn init_access( state: &<Commands<'_, '_> as SystemParam>::State, system_meta: &mut SystemMeta, system_access: &mut SystemAccess, world: &mut World, )
Source§fn apply(
state: &mut <Commands<'_, '_> as SystemParam>::State,
system_meta: &SystemMeta,
world: &mut World,
)
fn apply( state: &mut <Commands<'_, '_> as SystemParam>::State, system_meta: &SystemMeta, world: &mut World, )
SystemParam’s state.
This is used to apply Commands during ApplyDeferred.Source§fn queue(
state: &mut <Commands<'_, '_> as SystemParam>::State,
system_meta: &SystemMeta,
world: DeferredWorld<'_>,
)
fn queue( state: &mut <Commands<'_, '_> as SystemParam>::State, system_meta: &SystemMeta, world: DeferredWorld<'_>, )
ApplyDeferred.Source§unsafe fn get_param<'w, 's>(
state: &'s mut <Commands<'_, '_> as SystemParam>::State,
system_meta: &SystemMeta,
world: UnsafeWorldCell<'w>,
change_tick: Tick,
) -> Result<<Commands<'_, '_> as SystemParam>::Item<'w, 's>, SystemParamValidationError>
unsafe fn get_param<'w, 's>( state: &'s mut <Commands<'_, '_> as SystemParam>::State, system_meta: &SystemMeta, world: UnsafeWorldCell<'w>, change_tick: Tick, ) -> Result<<Commands<'_, '_> as SystemParam>::Item<'w, 's>, SystemParamValidationError>
SystemParamFunction. Read moreAuto Trait Implementations§
impl<'w, 's> !UnwindSafe for Commands<'w, 's>
impl<'w, 's> Freeze for Commands<'w, 's>
impl<'w, 's> RefUnwindSafe for Commands<'w, 's>
impl<'w, 's> Unpin for Commands<'w, 's>
impl<'w, 's> UnsafeUnpin for Commands<'w, 's>
Blanket Implementations§
Source§impl<T, U> AsBindGroupShaderType<U> for T
impl<T, U> AsBindGroupShaderType<U> for T
Source§fn as_bind_group_shader_type(&self, _images: &RenderAssets<GpuImage>) -> U
fn as_bind_group_shader_type(&self, _images: &RenderAssets<GpuImage>) -> U
T ShaderType for self. When used in AsBindGroup
derives, it is safe to assume that all images in self exist.Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
impl<T> ConditionalSend for Twhere
T: Send,
Source§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
Source§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>, which can then be
downcast into Box<dyn ConcreteType> where ConcreteType implements Trait.Source§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Rc<Trait> (where Trait: Downcast) to Rc<Any>, which can then be further
downcast into Rc<ConcreteType> where ConcreteType implements Trait.Source§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
&Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &Any’s vtable from &Trait’s.Source§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &mut Any’s vtable from &mut Trait’s.Source§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
Source§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>. Box<dyn Any> can
then be further downcast into Box<ConcreteType> where ConcreteType implements Trait.Source§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be
further downcast into Rc<ConcreteType> where ConcreteType implements Trait.Source§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
&Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &Any’s vtable from &Trait’s.Source§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &mut Any’s vtable from &mut Trait’s.Source§impl<T> DowncastSend for T
impl<T> DowncastSend for T
Source§impl<T> DowncastSync for T
impl<T> DowncastSync for T
impl<S, T> Duplex<S> for Twhere
T: FromSample<S> + ToSample<S>,
impl<T> ErasedDestructor for Twhere
T: 'static,
Source§impl<T> FmtForward for T
impl<T> FmtForward for T
Source§fn fmt_binary(self) -> FmtBinary<Self>where
Self: Binary,
fn fmt_binary(self) -> FmtBinary<Self>where
Self: Binary,
self to use its Binary implementation when Debug-formatted.Source§fn fmt_display(self) -> FmtDisplay<Self>where
Self: Display,
fn fmt_display(self) -> FmtDisplay<Self>where
Self: Display,
self to use its Display implementation when
Debug-formatted.Source§fn fmt_lower_exp(self) -> FmtLowerExp<Self>where
Self: LowerExp,
fn fmt_lower_exp(self) -> FmtLowerExp<Self>where
Self: LowerExp,
self to use its LowerExp implementation when
Debug-formatted.Source§fn fmt_lower_hex(self) -> FmtLowerHex<Self>where
Self: LowerHex,
fn fmt_lower_hex(self) -> FmtLowerHex<Self>where
Self: LowerHex,
self to use its LowerHex implementation when
Debug-formatted.Source§fn fmt_octal(self) -> FmtOctal<Self>where
Self: Octal,
fn fmt_octal(self) -> FmtOctal<Self>where
Self: Octal,
self to use its Octal implementation when Debug-formatted.Source§fn fmt_pointer(self) -> FmtPointer<Self>where
Self: Pointer,
fn fmt_pointer(self) -> FmtPointer<Self>where
Self: Pointer,
self to use its Pointer implementation when
Debug-formatted.Source§fn fmt_upper_exp(self) -> FmtUpperExp<Self>where
Self: UpperExp,
fn fmt_upper_exp(self) -> FmtUpperExp<Self>where
Self: UpperExp,
self to use its UpperExp implementation when
Debug-formatted.Source§fn fmt_upper_hex(self) -> FmtUpperHex<Self>where
Self: UpperHex,
fn fmt_upper_hex(self) -> FmtUpperHex<Self>where
Self: UpperHex,
self to use its UpperHex implementation when
Debug-formatted.Source§impl<S> FromSample<S> for S
impl<S> FromSample<S> for S
fn from_sample_(s: S) -> S
Source§impl<T, W> HasTypeWitness<W> for Twhere
W: MakeTypeWitness<Arg = T>,
T: ?Sized,
impl<T, W> HasTypeWitness<W> for Twhere
W: MakeTypeWitness<Arg = T>,
T: ?Sized,
Source§impl<T> Identity for Twhere
T: ?Sized,
impl<T> Identity for Twhere
T: ?Sized,
Source§impl<T> InitializeFromFunction<T> for T
impl<T> InitializeFromFunction<T> for T
Source§fn initialize_from_function(f: fn() -> T) -> T
fn initialize_from_function(f: fn() -> T) -> T
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§impl<T> IntoResult<T> for T
impl<T> IntoResult<T> for T
Source§fn into_result(self) -> Result<T, RunSystemError>
fn into_result(self) -> Result<T, RunSystemError>
Source§impl<F, T> IntoSample<T> for Fwhere
T: FromSample<F>,
impl<F, T> IntoSample<T> for Fwhere
T: FromSample<F>,
fn into_sample(self) -> T
Source§impl<T> Pipe for Twhere
T: ?Sized,
impl<T> Pipe for Twhere
T: ?Sized,
Source§fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> Rwhere
Self: Sized,
fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> Rwhere
Self: Sized,
Source§fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> Rwhere
R: 'a,
fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> Rwhere
R: 'a,
self and passes that borrow into the pipe function. Read moreSource§fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> Rwhere
R: 'a,
fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> Rwhere
R: 'a,
self and passes that borrow into the pipe function. Read moreSource§fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
Source§fn pipe_borrow_mut<'a, B, R>(
&'a mut self,
func: impl FnOnce(&'a mut B) -> R,
) -> R
fn pipe_borrow_mut<'a, B, R>( &'a mut self, func: impl FnOnce(&'a mut B) -> R, ) -> R
Source§fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
self, then passes self.as_ref() into the pipe function.Source§fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
self, then passes self.as_mut() into the pipe
function.Source§fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
self, then passes self.deref() into the pipe function.impl<T> Read<Exclusive, BecauseExclusive> for Twhere
T: ?Sized,
impl<T> Settings for T
Source§impl<Ret> SpawnIfAsync<(), Ret> for Ret
impl<Ret> SpawnIfAsync<(), Ret> for Ret
Source§impl<T, O> SuperFrom<T> for Owhere
O: From<T>,
impl<T, O> SuperFrom<T> for Owhere
O: From<T>,
Source§fn super_from(input: T) -> O
fn super_from(input: T) -> O
Source§impl<T, O, M> SuperInto<O, M> for Twhere
O: SuperFrom<T, M>,
impl<T, O, M> SuperInto<O, M> for Twhere
O: SuperFrom<T, M>,
Source§fn super_into(self) -> O
fn super_into(self) -> O
Source§impl<T> Tap for T
impl<T> Tap for T
Source§fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
Borrow<B> of a value. Read moreSource§fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
BorrowMut<B> of a value. Read moreSource§fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
AsRef<R> view of a value. Read moreSource§fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
AsMut<R> view of a value. Read moreSource§fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
Deref::Target of a value. Read moreSource§fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
Deref::Target of a value. Read moreSource§fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self
fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self
.tap() only in debug builds, and is erased in release builds.Source§fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self
fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self
.tap_mut() only in debug builds, and is erased in release
builds.Source§fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
.tap_borrow() only in debug builds, and is erased in release
builds.Source§fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
.tap_borrow_mut() only in debug builds, and is erased in release
builds.Source§fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
.tap_ref() only in debug builds, and is erased in release
builds.Source§fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
.tap_ref_mut() only in debug builds, and is erased in release
builds.Source§fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
.tap_deref() only in debug builds, and is erased in release
builds.