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 default error handler panics.
It can be configured by setting the GLOBAL_ERROR_HANDLER
.
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,
entities: &'w Entities,
) -> Commands<'w, 's>
pub fn new_from_entities( queue: &'s mut CommandQueue, entities: &'w Entities, ) -> Commands<'w, 's>
Returns a new Commands
instance from a CommandQueue
and an Entities
reference.
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.
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
spawn
to spawn an entity with components.spawn_batch
to spawn many entities with the same combination of components.
Examples found in repository?
52fn spawn_tasks(mut commands: Commands) {
53 let thread_pool = AsyncComputeTaskPool::get();
54 for x in 0..NUM_CUBES {
55 for y in 0..NUM_CUBES {
56 for z in 0..NUM_CUBES {
57 // Spawn new task on the AsyncComputeTaskPool; the task will be
58 // executed in the background, and the Task future returned by
59 // spawn() can be used to poll for the result
60 let entity = commands.spawn_empty().id();
61 let task = thread_pool.spawn(async move {
62 let duration = Duration::from_secs_f32(rand::thread_rng().gen_range(0.05..5.0));
63
64 // Pretend this is a time-intensive function. :)
65 async_std::task::sleep(duration).await;
66
67 // Such hard work, all done!
68 let transform = Transform::from_xyz(x as f32, y as f32, z as f32);
69 let mut command_queue = CommandQueue::default();
70
71 // we use a raw command queue to pass a FnOnce(&mut World) back to be
72 // applied in a deferred manner.
73 command_queue.push(move |world: &mut World| {
74 let (box_mesh_handle, box_material_handle) = {
75 let mut system_state = SystemState::<(
76 Res<BoxMeshHandle>,
77 Res<BoxMaterialHandle>,
78 )>::new(world);
79 let (box_mesh_handle, box_material_handle) =
80 system_state.get_mut(world);
81
82 (box_mesh_handle.clone(), box_material_handle.clone())
83 };
84
85 world
86 .entity_mut(entity)
87 // Add our new `Mesh3d` and `MeshMaterial3d` to our tagged entity
88 .insert((
89 Mesh3d(box_mesh_handle),
90 MeshMaterial3d(box_material_handle),
91 transform,
92 ))
93 // Task is complete, so remove task component from entity
94 .remove::<ComputeTransform>();
95 });
96
97 command_queue
98 });
99
100 // Spawn new entity and add our new task as a component
101 commands.entity(entity).insert(ComputeTransform(task));
102 }
103 }
104 }
105}
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::thread_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.r#gen::<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_empty
to spawn an entity without any components.spawn_batch
to spawn many entities with the same combination of components.
Examples found in repository?
44fn setup(mut commands: Commands) {
45 commands.spawn(Camera2d);
46}
47
48mod splash {
49 use bevy::prelude::*;
50
51 use super::{despawn_screen, GameState};
52
53 // This plugin will display a splash screen with Bevy logo for 1 second before switching to the menu
54 pub fn splash_plugin(app: &mut App) {
55 // As this plugin is managing the splash screen, it will focus on the state `GameState::Splash`
56 app
57 // When entering the state, spawn everything needed for this screen
58 .add_systems(OnEnter(GameState::Splash), splash_setup)
59 // While in this state, run the `countdown` system
60 .add_systems(Update, countdown.run_if(in_state(GameState::Splash)))
61 // When exiting the state, despawn everything that was spawned for this screen
62 .add_systems(OnExit(GameState::Splash), despawn_screen::<OnSplashScreen>);
63 }
64
65 // Tag component used to tag entities added on the splash screen
66 #[derive(Component)]
67 struct OnSplashScreen;
68
69 // Newtype to use a `Timer` for this screen as a resource
70 #[derive(Resource, Deref, DerefMut)]
71 struct SplashTimer(Timer);
72
73 fn splash_setup(mut commands: Commands, asset_server: Res<AssetServer>) {
74 let icon = asset_server.load("branding/icon.png");
75 // Display the logo
76 commands.spawn((
77 Node {
78 align_items: AlignItems::Center,
79 justify_content: JustifyContent::Center,
80 width: Val::Percent(100.0),
81 height: Val::Percent(100.0),
82 ..default()
83 },
84 OnSplashScreen,
85 children![(
86 ImageNode::new(icon),
87 Node {
88 // This will set the logo to be 200px wide, and auto adjust its height
89 width: Val::Px(200.0),
90 ..default()
91 },
92 )],
93 ));
94 // Insert the timer as a resource
95 commands.insert_resource(SplashTimer(Timer::from_seconds(1.0, TimerMode::Once)));
96 }
97
98 // Tick the timer, and change state when finished
99 fn countdown(
100 mut game_state: ResMut<NextState<GameState>>,
101 time: Res<Time>,
102 mut timer: ResMut<SplashTimer>,
103 ) {
104 if timer.tick(time.delta()).finished() {
105 game_state.set(GameState::Menu);
106 }
107 }
108}
109
110mod game {
111 use bevy::{
112 color::palettes::basic::{BLUE, LIME},
113 prelude::*,
114 };
115
116 use super::{despawn_screen, DisplayQuality, GameState, Volume, TEXT_COLOR};
117
118 // This plugin will contain the game. In this case, it's just be a screen that will
119 // display the current settings for 5 seconds before returning to the menu
120 pub fn game_plugin(app: &mut App) {
121 app.add_systems(OnEnter(GameState::Game), game_setup)
122 .add_systems(Update, game.run_if(in_state(GameState::Game)))
123 .add_systems(OnExit(GameState::Game), despawn_screen::<OnGameScreen>);
124 }
125
126 // Tag component used to tag entities added on the game screen
127 #[derive(Component)]
128 struct OnGameScreen;
129
130 #[derive(Resource, Deref, DerefMut)]
131 struct GameTimer(Timer);
132
133 fn game_setup(
134 mut commands: Commands,
135 display_quality: Res<DisplayQuality>,
136 volume: Res<Volume>,
137 ) {
138 commands.spawn((
139 Node {
140 width: Val::Percent(100.0),
141 height: Val::Percent(100.0),
142 // center children
143 align_items: AlignItems::Center,
144 justify_content: JustifyContent::Center,
145 ..default()
146 },
147 OnGameScreen,
148 children![(
149 Node {
150 // This will display its children in a column, from top to bottom
151 flex_direction: FlexDirection::Column,
152 // `align_items` will align children on the cross axis. Here the main axis is
153 // vertical (column), so the cross axis is horizontal. This will center the
154 // children
155 align_items: AlignItems::Center,
156 ..default()
157 },
158 BackgroundColor(Color::BLACK),
159 children![
160 (
161 Text::new("Will be back to the menu shortly..."),
162 TextFont {
163 font_size: 67.0,
164 ..default()
165 },
166 TextColor(TEXT_COLOR),
167 Node {
168 margin: UiRect::all(Val::Px(50.0)),
169 ..default()
170 },
171 ),
172 (
173 Text::default(),
174 Node {
175 margin: UiRect::all(Val::Px(50.0)),
176 ..default()
177 },
178 children![
179 (
180 TextSpan(format!("quality: {:?}", *display_quality)),
181 TextFont {
182 font_size: 50.0,
183 ..default()
184 },
185 TextColor(BLUE.into()),
186 ),
187 (
188 TextSpan::new(" - "),
189 TextFont {
190 font_size: 50.0,
191 ..default()
192 },
193 TextColor(TEXT_COLOR),
194 ),
195 (
196 TextSpan(format!("volume: {:?}", *volume)),
197 TextFont {
198 font_size: 50.0,
199 ..default()
200 },
201 TextColor(LIME.into()),
202 ),
203 ]
204 ),
205 ]
206 )],
207 ));
208 // Spawn a 5 seconds timer to trigger going back to the menu
209 commands.insert_resource(GameTimer(Timer::from_seconds(5.0, TimerMode::Once)));
210 }
211
212 // Tick the timer, and change state when finished
213 fn game(
214 time: Res<Time>,
215 mut game_state: ResMut<NextState<GameState>>,
216 mut timer: ResMut<GameTimer>,
217 ) {
218 if timer.tick(time.delta()).finished() {
219 game_state.set(GameState::Menu);
220 }
221 }
222}
223
224mod menu {
225 use bevy::{
226 app::AppExit,
227 color::palettes::css::CRIMSON,
228 ecs::spawn::{SpawnIter, SpawnWith},
229 prelude::*,
230 };
231
232 use super::{despawn_screen, DisplayQuality, GameState, Volume, TEXT_COLOR};
233
234 // This plugin manages the menu, with 5 different screens:
235 // - a main menu with "New Game", "Settings", "Quit"
236 // - a settings menu with two submenus and a back button
237 // - two settings screen with a setting that can be set and a back button
238 pub fn menu_plugin(app: &mut App) {
239 app
240 // At start, the menu is not enabled. This will be changed in `menu_setup` when
241 // entering the `GameState::Menu` state.
242 // Current screen in the menu is handled by an independent state from `GameState`
243 .init_state::<MenuState>()
244 .add_systems(OnEnter(GameState::Menu), menu_setup)
245 // Systems to handle the main menu screen
246 .add_systems(OnEnter(MenuState::Main), main_menu_setup)
247 .add_systems(OnExit(MenuState::Main), despawn_screen::<OnMainMenuScreen>)
248 // Systems to handle the settings menu screen
249 .add_systems(OnEnter(MenuState::Settings), settings_menu_setup)
250 .add_systems(
251 OnExit(MenuState::Settings),
252 despawn_screen::<OnSettingsMenuScreen>,
253 )
254 // Systems to handle the display settings screen
255 .add_systems(
256 OnEnter(MenuState::SettingsDisplay),
257 display_settings_menu_setup,
258 )
259 .add_systems(
260 Update,
261 (setting_button::<DisplayQuality>.run_if(in_state(MenuState::SettingsDisplay)),),
262 )
263 .add_systems(
264 OnExit(MenuState::SettingsDisplay),
265 despawn_screen::<OnDisplaySettingsMenuScreen>,
266 )
267 // Systems to handle the sound settings screen
268 .add_systems(OnEnter(MenuState::SettingsSound), sound_settings_menu_setup)
269 .add_systems(
270 Update,
271 setting_button::<Volume>.run_if(in_state(MenuState::SettingsSound)),
272 )
273 .add_systems(
274 OnExit(MenuState::SettingsSound),
275 despawn_screen::<OnSoundSettingsMenuScreen>,
276 )
277 // Common systems to all screens that handles buttons behavior
278 .add_systems(
279 Update,
280 (menu_action, button_system).run_if(in_state(GameState::Menu)),
281 );
282 }
283
284 // State used for the current menu screen
285 #[derive(Clone, Copy, Default, Eq, PartialEq, Debug, Hash, States)]
286 enum MenuState {
287 Main,
288 Settings,
289 SettingsDisplay,
290 SettingsSound,
291 #[default]
292 Disabled,
293 }
294
295 // Tag component used to tag entities added on the main menu screen
296 #[derive(Component)]
297 struct OnMainMenuScreen;
298
299 // Tag component used to tag entities added on the settings menu screen
300 #[derive(Component)]
301 struct OnSettingsMenuScreen;
302
303 // Tag component used to tag entities added on the display settings menu screen
304 #[derive(Component)]
305 struct OnDisplaySettingsMenuScreen;
306
307 // Tag component used to tag entities added on the sound settings menu screen
308 #[derive(Component)]
309 struct OnSoundSettingsMenuScreen;
310
311 const NORMAL_BUTTON: Color = Color::srgb(0.15, 0.15, 0.15);
312 const HOVERED_BUTTON: Color = Color::srgb(0.25, 0.25, 0.25);
313 const HOVERED_PRESSED_BUTTON: Color = Color::srgb(0.25, 0.65, 0.25);
314 const PRESSED_BUTTON: Color = Color::srgb(0.35, 0.75, 0.35);
315
316 // Tag component used to mark which setting is currently selected
317 #[derive(Component)]
318 struct SelectedOption;
319
320 // All actions that can be triggered from a button click
321 #[derive(Component)]
322 enum MenuButtonAction {
323 Play,
324 Settings,
325 SettingsDisplay,
326 SettingsSound,
327 BackToMainMenu,
328 BackToSettings,
329 Quit,
330 }
331
332 // This system handles changing all buttons color based on mouse interaction
333 fn button_system(
334 mut interaction_query: Query<
335 (&Interaction, &mut BackgroundColor, Option<&SelectedOption>),
336 (Changed<Interaction>, With<Button>),
337 >,
338 ) {
339 for (interaction, mut background_color, selected) in &mut interaction_query {
340 *background_color = match (*interaction, selected) {
341 (Interaction::Pressed, _) | (Interaction::None, Some(_)) => PRESSED_BUTTON.into(),
342 (Interaction::Hovered, Some(_)) => HOVERED_PRESSED_BUTTON.into(),
343 (Interaction::Hovered, None) => HOVERED_BUTTON.into(),
344 (Interaction::None, None) => NORMAL_BUTTON.into(),
345 }
346 }
347 }
348
349 // This system updates the settings when a new value for a setting is selected, and marks
350 // the button as the one currently selected
351 fn setting_button<T: Resource + Component + PartialEq + Copy>(
352 interaction_query: Query<(&Interaction, &T, Entity), (Changed<Interaction>, With<Button>)>,
353 selected_query: Single<(Entity, &mut BackgroundColor), With<SelectedOption>>,
354 mut commands: Commands,
355 mut setting: ResMut<T>,
356 ) {
357 let (previous_button, mut previous_button_color) = selected_query.into_inner();
358 for (interaction, button_setting, entity) in &interaction_query {
359 if *interaction == Interaction::Pressed && *setting != *button_setting {
360 *previous_button_color = NORMAL_BUTTON.into();
361 commands.entity(previous_button).remove::<SelectedOption>();
362 commands.entity(entity).insert(SelectedOption);
363 *setting = *button_setting;
364 }
365 }
366 }
367
368 fn menu_setup(mut menu_state: ResMut<NextState<MenuState>>) {
369 menu_state.set(MenuState::Main);
370 }
371
372 fn main_menu_setup(mut commands: Commands, asset_server: Res<AssetServer>) {
373 // Common style for all buttons on the screen
374 let button_node = Node {
375 width: Val::Px(300.0),
376 height: Val::Px(65.0),
377 margin: UiRect::all(Val::Px(20.0)),
378 justify_content: JustifyContent::Center,
379 align_items: AlignItems::Center,
380 ..default()
381 };
382 let button_icon_node = Node {
383 width: Val::Px(30.0),
384 // This takes the icons out of the flexbox flow, to be positioned exactly
385 position_type: PositionType::Absolute,
386 // The icon will be close to the left border of the button
387 left: Val::Px(10.0),
388 ..default()
389 };
390 let button_text_font = TextFont {
391 font_size: 33.0,
392 ..default()
393 };
394
395 let right_icon = asset_server.load("textures/Game Icons/right.png");
396 let wrench_icon = asset_server.load("textures/Game Icons/wrench.png");
397 let exit_icon = asset_server.load("textures/Game Icons/exitRight.png");
398
399 commands.spawn((
400 Node {
401 width: Val::Percent(100.0),
402 height: Val::Percent(100.0),
403 align_items: AlignItems::Center,
404 justify_content: JustifyContent::Center,
405 ..default()
406 },
407 OnMainMenuScreen,
408 children![(
409 Node {
410 flex_direction: FlexDirection::Column,
411 align_items: AlignItems::Center,
412 ..default()
413 },
414 BackgroundColor(CRIMSON.into()),
415 children![
416 // Display the game name
417 (
418 Text::new("Bevy Game Menu UI"),
419 TextFont {
420 font_size: 67.0,
421 ..default()
422 },
423 TextColor(TEXT_COLOR),
424 Node {
425 margin: UiRect::all(Val::Px(50.0)),
426 ..default()
427 },
428 ),
429 // Display three buttons for each action available from the main menu:
430 // - new game
431 // - settings
432 // - quit
433 (
434 Button,
435 button_node.clone(),
436 BackgroundColor(NORMAL_BUTTON),
437 MenuButtonAction::Play,
438 children![
439 (ImageNode::new(right_icon), button_icon_node.clone()),
440 (
441 Text::new("New Game"),
442 button_text_font.clone(),
443 TextColor(TEXT_COLOR),
444 ),
445 ]
446 ),
447 (
448 Button,
449 button_node.clone(),
450 BackgroundColor(NORMAL_BUTTON),
451 MenuButtonAction::Settings,
452 children![
453 (ImageNode::new(wrench_icon), button_icon_node.clone()),
454 (
455 Text::new("Settings"),
456 button_text_font.clone(),
457 TextColor(TEXT_COLOR),
458 ),
459 ]
460 ),
461 (
462 Button,
463 button_node,
464 BackgroundColor(NORMAL_BUTTON),
465 MenuButtonAction::Quit,
466 children![
467 (ImageNode::new(exit_icon), button_icon_node),
468 (Text::new("Quit"), button_text_font, TextColor(TEXT_COLOR),),
469 ]
470 ),
471 ]
472 )],
473 ));
474 }
475
476 fn settings_menu_setup(mut commands: Commands) {
477 let button_node = Node {
478 width: Val::Px(200.0),
479 height: Val::Px(65.0),
480 margin: UiRect::all(Val::Px(20.0)),
481 justify_content: JustifyContent::Center,
482 align_items: AlignItems::Center,
483 ..default()
484 };
485
486 let button_text_style = (
487 TextFont {
488 font_size: 33.0,
489 ..default()
490 },
491 TextColor(TEXT_COLOR),
492 );
493
494 commands.spawn((
495 Node {
496 width: Val::Percent(100.0),
497 height: Val::Percent(100.0),
498 align_items: AlignItems::Center,
499 justify_content: JustifyContent::Center,
500 ..default()
501 },
502 OnSettingsMenuScreen,
503 children![(
504 Node {
505 flex_direction: FlexDirection::Column,
506 align_items: AlignItems::Center,
507 ..default()
508 },
509 BackgroundColor(CRIMSON.into()),
510 Children::spawn(SpawnIter(
511 [
512 (MenuButtonAction::SettingsDisplay, "Display"),
513 (MenuButtonAction::SettingsSound, "Sound"),
514 (MenuButtonAction::BackToMainMenu, "Back"),
515 ]
516 .into_iter()
517 .map(move |(action, text)| {
518 (
519 Button,
520 button_node.clone(),
521 BackgroundColor(NORMAL_BUTTON),
522 action,
523 children![(Text::new(text), button_text_style.clone())],
524 )
525 })
526 ))
527 )],
528 ));
529 }
530
531 fn display_settings_menu_setup(mut commands: Commands, display_quality: Res<DisplayQuality>) {
532 fn button_node() -> Node {
533 Node {
534 width: Val::Px(200.0),
535 height: Val::Px(65.0),
536 margin: UiRect::all(Val::Px(20.0)),
537 justify_content: JustifyContent::Center,
538 align_items: AlignItems::Center,
539 ..default()
540 }
541 }
542 fn button_text_style() -> impl Bundle {
543 (
544 TextFont {
545 font_size: 33.0,
546 ..default()
547 },
548 TextColor(TEXT_COLOR),
549 )
550 }
551
552 let display_quality = *display_quality;
553 commands.spawn((
554 Node {
555 width: Val::Percent(100.0),
556 height: Val::Percent(100.0),
557 align_items: AlignItems::Center,
558 justify_content: JustifyContent::Center,
559 ..default()
560 },
561 OnDisplaySettingsMenuScreen,
562 children![(
563 Node {
564 flex_direction: FlexDirection::Column,
565 align_items: AlignItems::Center,
566 ..default()
567 },
568 BackgroundColor(CRIMSON.into()),
569 children![
570 // Create a new `Node`, this time not setting its `flex_direction`. It will
571 // use the default value, `FlexDirection::Row`, from left to right.
572 (
573 Node {
574 align_items: AlignItems::Center,
575 ..default()
576 },
577 BackgroundColor(CRIMSON.into()),
578 Children::spawn((
579 // Display a label for the current setting
580 Spawn((Text::new("Display Quality"), button_text_style())),
581 SpawnWith(move |parent: &mut ChildSpawner| {
582 for quality_setting in [
583 DisplayQuality::Low,
584 DisplayQuality::Medium,
585 DisplayQuality::High,
586 ] {
587 let mut entity = parent.spawn((
588 Button,
589 Node {
590 width: Val::Px(150.0),
591 height: Val::Px(65.0),
592 ..button_node()
593 },
594 BackgroundColor(NORMAL_BUTTON),
595 quality_setting,
596 children![(
597 Text::new(format!("{quality_setting:?}")),
598 button_text_style(),
599 )],
600 ));
601 if display_quality == quality_setting {
602 entity.insert(SelectedOption);
603 }
604 }
605 })
606 ))
607 ),
608 // Display the back button to return to the settings screen
609 (
610 Button,
611 button_node(),
612 BackgroundColor(NORMAL_BUTTON),
613 MenuButtonAction::BackToSettings,
614 children![(Text::new("Back"), button_text_style())]
615 )
616 ]
617 )],
618 ));
619 }
620
621 fn sound_settings_menu_setup(mut commands: Commands, volume: Res<Volume>) {
622 let button_node = Node {
623 width: Val::Px(200.0),
624 height: Val::Px(65.0),
625 margin: UiRect::all(Val::Px(20.0)),
626 justify_content: JustifyContent::Center,
627 align_items: AlignItems::Center,
628 ..default()
629 };
630 let button_text_style = (
631 TextFont {
632 font_size: 33.0,
633 ..default()
634 },
635 TextColor(TEXT_COLOR),
636 );
637
638 let volume = *volume;
639 let button_node_clone = button_node.clone();
640 commands.spawn((
641 Node {
642 width: Val::Percent(100.0),
643 height: Val::Percent(100.0),
644 align_items: AlignItems::Center,
645 justify_content: JustifyContent::Center,
646 ..default()
647 },
648 OnSoundSettingsMenuScreen,
649 children![(
650 Node {
651 flex_direction: FlexDirection::Column,
652 align_items: AlignItems::Center,
653 ..default()
654 },
655 BackgroundColor(CRIMSON.into()),
656 children![
657 (
658 Node {
659 align_items: AlignItems::Center,
660 ..default()
661 },
662 BackgroundColor(CRIMSON.into()),
663 Children::spawn((
664 Spawn((Text::new("Volume"), button_text_style.clone())),
665 SpawnWith(move |parent: &mut ChildSpawner| {
666 for volume_setting in [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] {
667 let mut entity = parent.spawn((
668 Button,
669 Node {
670 width: Val::Px(30.0),
671 height: Val::Px(65.0),
672 ..button_node_clone.clone()
673 },
674 BackgroundColor(NORMAL_BUTTON),
675 Volume(volume_setting),
676 ));
677 if volume == Volume(volume_setting) {
678 entity.insert(SelectedOption);
679 }
680 }
681 })
682 ))
683 ),
684 (
685 Button,
686 button_node,
687 BackgroundColor(NORMAL_BUTTON),
688 MenuButtonAction::BackToSettings,
689 children![(Text::new("Back"), button_text_style)]
690 )
691 ]
692 )],
693 ));
694 }
More examples
221fn setup(mut commands: Commands) {
222 commands.spawn(Camera2d);
223}
224
225fn setup_game(mut commands: Commands, asset_server: Res<AssetServer>) {
226 commands.spawn(Sprite::from_image(asset_server.load("branding/icon.png")));
227 info!("Setup game");
228}
229
230fn teardown_game(mut commands: Commands, player: Single<Entity, With<Sprite>>) {
231 commands.entity(*player).despawn();
232 info!("Teardown game");
233}
234
235#[derive(Resource)]
236struct MenuData {
237 pub button_entity: Entity,
238}
239
240const NORMAL_BUTTON: Color = Color::srgb(0.15, 0.15, 0.15);
241const HOVERED_BUTTON: Color = Color::srgb(0.25, 0.25, 0.25);
242const PRESSED_BUTTON: Color = Color::srgb(0.35, 0.75, 0.35);
243
244fn setup_menu(mut commands: Commands) {
245 let button_entity = commands
246 .spawn((
247 Node {
248 // center button
249 width: Val::Percent(100.),
250 height: Val::Percent(100.),
251 justify_content: JustifyContent::Center,
252 align_items: AlignItems::Center,
253 ..default()
254 },
255 children![(
256 Button,
257 Node {
258 width: Val::Px(150.),
259 height: Val::Px(65.),
260 // horizontally center child text
261 justify_content: JustifyContent::Center,
262 // vertically center child text
263 align_items: AlignItems::Center,
264 ..default()
265 },
266 BackgroundColor(NORMAL_BUTTON),
267 children![(
268 Text::new("Play"),
269 TextFont {
270 font_size: 33.0,
271 ..default()
272 },
273 TextColor(Color::srgb(0.9, 0.9, 0.9)),
274 )]
275 )],
276 ))
277 .id();
278 commands.insert_resource(MenuData { button_entity });
279}
48fn setup(mut commands: Commands) {
49 commands.spawn(Camera2d);
50}
51
52fn setup_menu(mut commands: Commands) {
53 let button_entity = commands
54 .spawn((
55 Node {
56 // center button
57 width: Val::Percent(100.),
58 height: Val::Percent(100.),
59 justify_content: JustifyContent::Center,
60 align_items: AlignItems::Center,
61 ..default()
62 },
63 children![(
64 Button,
65 Node {
66 width: Val::Px(150.),
67 height: Val::Px(65.),
68 // horizontally center child text
69 justify_content: JustifyContent::Center,
70 // vertically center child text
71 align_items: AlignItems::Center,
72 ..default()
73 },
74 BackgroundColor(NORMAL_BUTTON),
75 children![(
76 Text::new("Play"),
77 TextFont {
78 font_size: 33.0,
79 ..default()
80 },
81 TextColor(Color::srgb(0.9, 0.9, 0.9)),
82 )],
83 )],
84 ))
85 .id();
86 commands.insert_resource(MenuData { button_entity });
87}
88
89fn menu(
90 mut next_state: ResMut<NextState<AppState>>,
91 mut interaction_query: Query<
92 (&Interaction, &mut BackgroundColor),
93 (Changed<Interaction>, With<Button>),
94 >,
95) {
96 for (interaction, mut color) in &mut interaction_query {
97 match *interaction {
98 Interaction::Pressed => {
99 *color = PRESSED_BUTTON.into();
100 next_state.set(AppState::InGame);
101 }
102 Interaction::Hovered => {
103 *color = HOVERED_BUTTON.into();
104 }
105 Interaction::None => {
106 *color = NORMAL_BUTTON.into();
107 }
108 }
109 }
110}
111
112fn cleanup_menu(mut commands: Commands, menu_data: Res<MenuData>) {
113 commands.entity(menu_data.button_entity).despawn();
114}
115
116fn setup_game(mut commands: Commands, asset_server: Res<AssetServer>) {
117 commands.spawn(Sprite::from_image(asset_server.load("branding/icon.png")));
118}
16fn setup_camera(mut commands: Commands) {
17 commands.spawn(Camera2d);
18}
19
20fn setup_sprites(mut commands: Commands, asset_server: Res<AssetServer>) {
21 let square = asset_server.load("textures/slice_square_2.png");
22 let banner = asset_server.load("branding/banner.png");
23
24 let rects = [
25 Rect {
26 size: Vec2::new(100., 225.),
27 text: "Stretched".to_string(),
28 transform: Transform::from_translation(Vec3::new(-570., 230., 0.)),
29 texture: square.clone(),
30 image_mode: SpriteImageMode::Auto,
31 },
32 Rect {
33 size: Vec2::new(100., 225.),
34 text: "Fill Center".to_string(),
35 transform: Transform::from_translation(Vec3::new(-450., 230., 0.)),
36 texture: square.clone(),
37 image_mode: SpriteImageMode::Scale(ScalingMode::FillCenter),
38 },
39 Rect {
40 size: Vec2::new(100., 225.),
41 text: "Fill Start".to_string(),
42 transform: Transform::from_translation(Vec3::new(-330., 230., 0.)),
43 texture: square.clone(),
44 image_mode: SpriteImageMode::Scale(ScalingMode::FillStart),
45 },
46 Rect {
47 size: Vec2::new(100., 225.),
48 text: "Fill End".to_string(),
49 transform: Transform::from_translation(Vec3::new(-210., 230., 0.)),
50 texture: square.clone(),
51 image_mode: SpriteImageMode::Scale(ScalingMode::FillEnd),
52 },
53 Rect {
54 size: Vec2::new(300., 100.),
55 text: "Fill Start Horizontal".to_string(),
56 transform: Transform::from_translation(Vec3::new(10., 290., 0.)),
57 texture: square.clone(),
58 image_mode: SpriteImageMode::Scale(ScalingMode::FillStart),
59 },
60 Rect {
61 size: Vec2::new(300., 100.),
62 text: "Fill End Horizontal".to_string(),
63 transform: Transform::from_translation(Vec3::new(10., 155., 0.)),
64 texture: square.clone(),
65 image_mode: SpriteImageMode::Scale(ScalingMode::FillEnd),
66 },
67 Rect {
68 size: Vec2::new(200., 200.),
69 text: "Fill Center".to_string(),
70 transform: Transform::from_translation(Vec3::new(280., 230., 0.)),
71 texture: banner.clone(),
72 image_mode: SpriteImageMode::Scale(ScalingMode::FillCenter),
73 },
74 Rect {
75 size: Vec2::new(200., 100.),
76 text: "Fill Center".to_string(),
77 transform: Transform::from_translation(Vec3::new(500., 230., 0.)),
78 texture: square.clone(),
79 image_mode: SpriteImageMode::Scale(ScalingMode::FillCenter),
80 },
81 Rect {
82 size: Vec2::new(100., 100.),
83 text: "Stretched".to_string(),
84 transform: Transform::from_translation(Vec3::new(-570., -40., 0.)),
85 texture: banner.clone(),
86 image_mode: SpriteImageMode::Auto,
87 },
88 Rect {
89 size: Vec2::new(200., 200.),
90 text: "Fit Center".to_string(),
91 transform: Transform::from_translation(Vec3::new(-400., -40., 0.)),
92 texture: banner.clone(),
93 image_mode: SpriteImageMode::Scale(ScalingMode::FitCenter),
94 },
95 Rect {
96 size: Vec2::new(200., 200.),
97 text: "Fit Start".to_string(),
98 transform: Transform::from_translation(Vec3::new(-180., -40., 0.)),
99 texture: banner.clone(),
100 image_mode: SpriteImageMode::Scale(ScalingMode::FitStart),
101 },
102 Rect {
103 size: Vec2::new(200., 200.),
104 text: "Fit End".to_string(),
105 transform: Transform::from_translation(Vec3::new(40., -40., 0.)),
106 texture: banner.clone(),
107 image_mode: SpriteImageMode::Scale(ScalingMode::FitEnd),
108 },
109 Rect {
110 size: Vec2::new(100., 200.),
111 text: "Fit Center".to_string(),
112 transform: Transform::from_translation(Vec3::new(210., -40., 0.)),
113 texture: banner.clone(),
114 image_mode: SpriteImageMode::Scale(ScalingMode::FitCenter),
115 },
116 ];
117
118 for rect in rects {
119 let mut cmd = commands.spawn((
120 Sprite {
121 image: rect.texture,
122 custom_size: Some(rect.size),
123 image_mode: rect.image_mode,
124 ..default()
125 },
126 rect.transform,
127 ));
128
129 cmd.with_children(|builder| {
130 builder.spawn((
131 Text2d::new(rect.text),
132 TextLayout::new_with_justify(JustifyText::Center),
133 TextFont::from_font_size(15.),
134 Transform::from_xyz(0., -0.5 * rect.size.y - 10., 0.),
135 bevy::sprite::Anchor::TopCenter,
136 ));
137 });
138 }
139}
140
141fn setup_texture_atlas(
142 mut commands: Commands,
143 asset_server: Res<AssetServer>,
144 mut texture_atlas_layouts: ResMut<Assets<TextureAtlasLayout>>,
145) {
146 commands.spawn(Camera2d);
147 let gabe = asset_server.load("textures/rpg/chars/gabe/gabe-idle-run.png");
148 let animation_indices_gabe = AnimationIndices { first: 0, last: 6 };
149 let gabe_atlas = TextureAtlas {
150 layout: texture_atlas_layouts.add(TextureAtlasLayout::from_grid(
151 UVec2::splat(24),
152 7,
153 1,
154 None,
155 None,
156 )),
157 index: animation_indices_gabe.first,
158 };
159
160 let sprite_sheets = [
161 SpriteSheet {
162 size: Vec2::new(120., 50.),
163 text: "Stretched".to_string(),
164 transform: Transform::from_translation(Vec3::new(-570., -200., 0.)),
165 texture: gabe.clone(),
166 image_mode: SpriteImageMode::Auto,
167 atlas: gabe_atlas.clone(),
168 indices: animation_indices_gabe.clone(),
169 timer: AnimationTimer(Timer::from_seconds(0.1, TimerMode::Repeating)),
170 },
171 SpriteSheet {
172 size: Vec2::new(120., 50.),
173 text: "Fill Center".to_string(),
174 transform: Transform::from_translation(Vec3::new(-570., -300., 0.)),
175 texture: gabe.clone(),
176 image_mode: SpriteImageMode::Scale(ScalingMode::FillCenter),
177 atlas: gabe_atlas.clone(),
178 indices: animation_indices_gabe.clone(),
179 timer: AnimationTimer(Timer::from_seconds(0.1, TimerMode::Repeating)),
180 },
181 SpriteSheet {
182 size: Vec2::new(120., 50.),
183 text: "Fill Start".to_string(),
184 transform: Transform::from_translation(Vec3::new(-430., -200., 0.)),
185 texture: gabe.clone(),
186 image_mode: SpriteImageMode::Scale(ScalingMode::FillStart),
187 atlas: gabe_atlas.clone(),
188 indices: animation_indices_gabe.clone(),
189 timer: AnimationTimer(Timer::from_seconds(0.1, TimerMode::Repeating)),
190 },
191 SpriteSheet {
192 size: Vec2::new(120., 50.),
193 text: "Fill End".to_string(),
194 transform: Transform::from_translation(Vec3::new(-430., -300., 0.)),
195 texture: gabe.clone(),
196 image_mode: SpriteImageMode::Scale(ScalingMode::FillEnd),
197 atlas: gabe_atlas.clone(),
198 indices: animation_indices_gabe.clone(),
199 timer: AnimationTimer(Timer::from_seconds(0.1, TimerMode::Repeating)),
200 },
201 SpriteSheet {
202 size: Vec2::new(50., 120.),
203 text: "Fill Center".to_string(),
204 transform: Transform::from_translation(Vec3::new(-300., -250., 0.)),
205 texture: gabe.clone(),
206 image_mode: SpriteImageMode::Scale(ScalingMode::FillCenter),
207 atlas: gabe_atlas.clone(),
208 indices: animation_indices_gabe.clone(),
209 timer: AnimationTimer(Timer::from_seconds(0.1, TimerMode::Repeating)),
210 },
211 SpriteSheet {
212 size: Vec2::new(50., 120.),
213 text: "Fill Start".to_string(),
214 transform: Transform::from_translation(Vec3::new(-190., -250., 0.)),
215 texture: gabe.clone(),
216 image_mode: SpriteImageMode::Scale(ScalingMode::FillStart),
217 atlas: gabe_atlas.clone(),
218 indices: animation_indices_gabe.clone(),
219 timer: AnimationTimer(Timer::from_seconds(0.1, TimerMode::Repeating)),
220 },
221 SpriteSheet {
222 size: Vec2::new(50., 120.),
223 text: "Fill End".to_string(),
224 transform: Transform::from_translation(Vec3::new(-90., -250., 0.)),
225 texture: gabe.clone(),
226 image_mode: SpriteImageMode::Scale(ScalingMode::FillEnd),
227 atlas: gabe_atlas.clone(),
228 indices: animation_indices_gabe.clone(),
229 timer: AnimationTimer(Timer::from_seconds(0.1, TimerMode::Repeating)),
230 },
231 SpriteSheet {
232 size: Vec2::new(120., 50.),
233 text: "Fit Center".to_string(),
234 transform: Transform::from_translation(Vec3::new(20., -200., 0.)),
235 texture: gabe.clone(),
236 image_mode: SpriteImageMode::Scale(ScalingMode::FitCenter),
237 atlas: gabe_atlas.clone(),
238 indices: animation_indices_gabe.clone(),
239 timer: AnimationTimer(Timer::from_seconds(0.1, TimerMode::Repeating)),
240 },
241 SpriteSheet {
242 size: Vec2::new(120., 50.),
243 text: "Fit Start".to_string(),
244 transform: Transform::from_translation(Vec3::new(20., -300., 0.)),
245 texture: gabe.clone(),
246 image_mode: SpriteImageMode::Scale(ScalingMode::FitStart),
247 atlas: gabe_atlas.clone(),
248 indices: animation_indices_gabe.clone(),
249 timer: AnimationTimer(Timer::from_seconds(0.1, TimerMode::Repeating)),
250 },
251 SpriteSheet {
252 size: Vec2::new(120., 50.),
253 text: "Fit End".to_string(),
254 transform: Transform::from_translation(Vec3::new(160., -200., 0.)),
255 texture: gabe.clone(),
256 image_mode: SpriteImageMode::Scale(ScalingMode::FitEnd),
257 atlas: gabe_atlas.clone(),
258 indices: animation_indices_gabe.clone(),
259 timer: AnimationTimer(Timer::from_seconds(0.1, TimerMode::Repeating)),
260 },
261 ];
262
263 for sprite_sheet in sprite_sheets {
264 let mut cmd = commands.spawn((
265 Sprite {
266 image_mode: sprite_sheet.image_mode,
267 custom_size: Some(sprite_sheet.size),
268 ..Sprite::from_atlas_image(sprite_sheet.texture.clone(), sprite_sheet.atlas.clone())
269 },
270 sprite_sheet.indices,
271 sprite_sheet.timer,
272 sprite_sheet.transform,
273 ));
274
275 cmd.with_children(|builder| {
276 builder.spawn((
277 Text2d::new(sprite_sheet.text),
278 TextLayout::new_with_justify(JustifyText::Center),
279 TextFont::from_font_size(15.),
280 Transform::from_xyz(0., -0.5 * sprite_sheet.size.y - 10., 0.),
281 bevy::sprite::Anchor::TopCenter,
282 ));
283 });
284 }
285}
- 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/3d/irradiance_volumes.rs
- examples/ui/button.rs
- examples/ecs/one_shot_systems.rs
- examples/scene/scene.rs
- examples/ui/viewport_debug.rs
- examples/audio/audio.rs
- examples/asset/custom_asset_reader.rs
- examples/window/transparent_window.rs
- examples/3d/mixed_lighting.rs
- examples/time/timers.rs
- examples/3d/reflection_probes.rs
- examples/2d/sprite.rs
- examples/asset/asset_decompression.rs
- examples/ecs/removal_detection.rs
- examples/2d/move_sprite.rs
- examples/app/logs.rs
- examples/audio/decodable.rs
- examples/testbed/ui.rs
- examples/ecs/change_detection.rs
- examples/3d/fog.rs
- examples/app/log_layers_ecs.rs
- examples/asset/multi_asset_sync.rs
- examples/2d/mesh2d.rs
- examples/ecs/component_hooks.rs
- examples/2d/sprite_flipping.rs
- examples/window/screenshot.rs
- examples/math/render_primitives.rs
- examples/ecs/generic_system.rs
- examples/movement/physics_in_fixed_timestep.rs
- examples/stress_tests/many_gizmos.rs
- examples/animation/gltf_skinned_mesh.rs
- examples/games/alien_cake_addict.rs
- examples/shader/animate_shader.rs
- examples/audio/pitch.rs
- examples/async_tasks/async_compute.rs
- examples/3d/query_gltf_primitives.rs
- examples/ecs/observer_propagation.rs
- examples/2d/sprite_tile.rs
- examples/3d/lightmaps.rs
- examples/shader/shader_material_2d.rs
- examples/shader/shader_material_wesl.rs
- examples/audio/audio_control.rs
- examples/shader/array_texture.rs
- examples/ecs/fallible_params.rs
- examples/3d/ssr.rs
- examples/2d/custom_gltf_vertex_attribute.rs
- examples/ecs/ecs_guide.rs
- examples/dev_tools/fps_overlay.rs
- examples/camera/2d_top_down_camera.rs
- examples/2d/pixel_grid_snap.rs
- examples/shader/fallback_image.rs
- examples/shader/custom_phase_item.rs
- examples/3d/motion_blur.rs
- examples/3d/3d_viewport_to_world.rs
- examples/gizmos/2d_gizmos.rs
- examples/3d/clustered_decals.rs
- examples/shader/shader_material.rs
- examples/shader/shader_material_glsl.rs
- examples/asset/extra_source.rs
- examples/shader/texture_binding_array.rs
- examples/ui/window_fallthrough.rs
- examples/asset/hot_asset_reloading.rs
- examples/ecs/parallel_query.rs
- examples/async_tasks/external_source_external_thread.rs
- examples/games/loading_screen.rs
- examples/2d/transparency_2d.rs
- examples/transforms/3d_rotation.rs
- examples/3d/rotate_environment_map.rs
- examples/transforms/scale.rs
- examples/shader/custom_vertex_attribute.rs
- examples/ecs/entity_disabling.rs
- tests/window/minimizing.rs
- tests/window/resizing.rs
- examples/3d/atmospheric_fog.rs
- examples/transforms/translation.rs
- examples/3d/load_gltf_extras.rs
- examples/animation/morph_targets.rs
- examples/shader/shader_defs.rs
- examples/3d/post_processing.rs
- examples/3d/clearcoat.rs
- examples/3d/3d_scene.rs
- examples/diagnostics/log_diagnostics.rs
- examples/asset/embedded_asset.rs
- examples/2d/sprite_sheet.rs
- examples/shader/custom_post_processing.rs
- examples/ui/font_atlas_debug.rs
- examples/animation/animation_graph.rs
- examples/shader/compute_shader_game_of_life.rs
- examples/3d/color_grading.rs
- examples/shader/shader_material_screenspace_texture.rs
- examples/3d/pcss.rs
- examples/3d/tonemapping.rs
- examples/camera/camera_orbit.rs
- examples/3d/edit_material_on_gltf.rs
- examples/shader/shader_material_bindless.rs
- examples/3d/anisotropy.rs
- examples/remote/server.rs
- examples/animation/animation_masks.rs
- examples/3d/parenting.rs
- examples/window/window_drag_move.rs
- examples/3d/animated_material.rs
- examples/3d/depth_of_field.rs
- examples/camera/custom_projection.rs
- examples/animation/animated_mesh_events.rs
- examples/3d/skybox.rs
- examples/3d/load_gltf.rs
- examples/3d/two_passes.rs
- examples/window/scale_factor_override.rs
- examples/3d/lines.rs
- examples/input/text_input.rs
- examples/stress_tests/many_materials.rs
- examples/animation/animated_mesh.rs
- examples/camera/2d_screen_shake.rs
- examples/shader/extended_material_bindless.rs
- examples/stress_tests/many_glyphs.rs
- examples/stress_tests/text_pipeline.rs
- examples/3d/update_gltf_scene.rs
- examples/shader/custom_render_phase.rs
- examples/3d/atmosphere.rs
- examples/3d/order_independent_transparency.rs
- examples/shader/storage_buffer.rs
- examples/2d/mesh2d_vertex_color_texture.rs
- examples/ecs/hierarchy.rs
- examples/3d/fog_volumes.rs
- examples/3d/generate_custom_mesh.rs
- examples/2d/wireframe_2d.rs
- examples/stress_tests/many_sprites.rs
- examples/audio/soundtrack.rs
- examples/animation/color_animation.rs
- examples/window/low_power.rs
- examples/audio/spatial_audio_2d.rs
- examples/movement/smooth_follow.rs
- examples/3d/mesh_ray_cast.rs
- examples/ui/relative_cursor_position.rs
- examples/3d/vertex_colors.rs
- examples/shader/extended_material.rs
- examples/picking/simple_picking.rs
- examples/shader/custom_shader_instancing.rs
- examples/ui/ui_material.rs
- examples/animation/animation_events.rs
- examples/games/contributors.rs
- examples/3d/orthographic.rs
- examples/testbed/2d.rs
- examples/shader/specialized_mesh_pipeline.rs
- examples/picking/debug_picking.rs
- examples/3d/spherical_area_lights.rs
- examples/2d/2d_shapes.rs
- examples/ecs/observers.rs
- examples/ui/ui_scaling.rs
- examples/math/bounding_2d.rs
- examples/transforms/transform.rs
- examples/2d/2d_viewport_to_world.rs
- examples/window/multiple_windows.rs
- examples/stress_tests/many_animated_sprites.rs
- examples/ui/ui_texture_atlas.rs
- examples/stress_tests/many_text2d.rs
- examples/gizmos/axes.rs
- examples/2d/bloom_2d.rs
- examples/ecs/relationships.rs
- examples/3d/occlusion_culling.rs
- examples/math/custom_primitives.rs
- examples/camera/first_person_view_model.rs
- examples/ui/ghost_nodes.rs
- examples/asset/alter_sprite.rs
- examples/app/headless_renderer.rs
- examples/ui/overflow_debug.rs
- examples/animation/eased_motion.rs
- examples/3d/ssao.rs
- examples/3d/wireframe.rs
- examples/stress_tests/transform_hierarchy.rs
- examples/stress_tests/many_buttons.rs
- examples/shader/automatic_instancing.rs
- examples/audio/spatial_audio_3d.rs
- examples/ecs/error_handling.rs
- examples/camera/projection_zoom.rs
- examples/2d/rotation.rs
- examples/ui/ui_texture_slice.rs
- examples/3d/visibility_range.rs
- examples/3d/specular_tint.rs
- examples/2d/sprite_animation.rs
- examples/math/cubic_splines.rs
- examples/testbed/3d.rs
- examples/2d/cpu_draw.rs
- examples/animation/animated_mesh_control.rs
- examples/stress_tests/many_cameras_lights.rs
- examples/3d/volumetric_fog.rs
- examples/3d/texture.rs
- examples/animation/animated_ui.rs
- examples/time/virtual_time.rs
- examples/3d/shadow_caster_receiver.rs
- examples/ui/ui_texture_slice_flip_and_tile.rs
- examples/window/monitor_info.rs
- examples/stress_tests/many_lights.rs
- examples/ui/size_constraints.rs
- examples/gizmos/3d_gizmos.rs
- examples/games/stepping.rs
- examples/3d/bloom_3d.rs
- examples/3d/anti_aliasing.rs
- examples/ui/transparency_ui.rs
- examples/transforms/align.rs
- examples/3d/decal.rs
- examples/math/random_sampling.rs
- examples/ui/render_ui_to_texture.rs
- examples/ui/ui_texture_atlas_slice.rs
- examples/shader/gpu_readback.rs
- examples/picking/sprite_picking.rs
- examples/2d/mesh2d_alpha_mode.rs
- examples/3d/scrolling_fog.rs
- examples/2d/mesh2d_arcs.rs
- examples/asset/repeated_texture.rs
- examples/ecs/iter_combinations.rs
- examples/ui/text_wrap_debug.rs
- examples/2d/mesh2d_manual.rs
- examples/asset/alter_mesh.rs
- examples/2d/sprite_slice.rs
- examples/3d/transparency_3d.rs
- examples/asset/asset_settings.rs
- examples/ui/text.rs
- examples/2d/mesh2d_repeated_texture.rs
- examples/3d/3d_shapes.rs
- examples/3d/meshlet.rs
- examples/gizmos/light_gizmos.rs
- examples/3d/render_to_texture.rs
- examples/3d/pbr.rs
- examples/3d/spotlight.rs
- examples/asset/asset_loading.rs
- examples/3d/auto_exposure.rs
- examples/ui/overflow.rs
- examples/ui/flex_layout.rs
- examples/ui/overflow_clip_margin.rs
- examples/animation/easing_functions.rs
- examples/stress_tests/bevymark.rs
- examples/shader/shader_prepass.rs
- examples/ui/display_and_visibility.rs
- examples/ui/tab_navigation.rs
- examples/games/breakout.rs
- examples/picking/mesh_picking.rs
- examples/3d/shadow_biases.rs
- examples/stress_tests/many_foxes.rs
- examples/3d/split_screen.rs
- examples/ui/z_index.rs
- examples/games/desk_toy.rs
- examples/2d/text2d.rs
- examples/math/sampling_primitives.rs
- examples/2d/texture_atlas.rs
- examples/3d/parallax_mapping.rs
- examples/ui/directional_navigation.rs
- examples/3d/deferred_rendering.rs
- examples/animation/custom_skinned_mesh.rs
- examples/3d/blend_modes.rs
- examples/stress_tests/many_cubes.rs
- examples/3d/lighting.rs
- examples/animation/animated_transform.rs
- examples/ui/box_shadow.rs
- examples/3d/camera_sub_view.rs
- examples/ui/text_debug.rs
- examples/ui/grid.rs
- examples/3d/transmission.rs
- examples/ui/borders.rs
- examples/ui/scroll.rs
- examples/testbed/full_ui.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_entity
for the fallible version.
Examples found in repository?
165fn cleanup_menu(mut commands: Commands, menu_data: Res<MenuData>) {
166 commands.entity(menu_data.button_entity).despawn();
167}
168
169const SPEED: f32 = 100.0;
170fn movement(
171 time: Res<Time>,
172 input: Res<ButtonInput<KeyCode>>,
173 mut query: Query<&mut Transform, With<Sprite>>,
174) {
175 for mut transform in &mut query {
176 let mut direction = Vec3::ZERO;
177 if input.pressed(KeyCode::ArrowLeft) {
178 direction.x -= 1.0;
179 }
180 if input.pressed(KeyCode::ArrowRight) {
181 direction.x += 1.0;
182 }
183 if input.pressed(KeyCode::ArrowUp) {
184 direction.y += 1.0;
185 }
186 if input.pressed(KeyCode::ArrowDown) {
187 direction.y -= 1.0;
188 }
189
190 if direction != Vec3::ZERO {
191 transform.translation += direction.normalize() * SPEED * time.delta_secs();
192 }
193 }
194}
195
196fn change_color(time: Res<Time>, mut query: Query<&mut Sprite>) {
197 for mut sprite in &mut query {
198 let new_color = LinearRgba {
199 blue: ops::sin(time.elapsed_secs() * 0.5) + 2.0,
200 ..LinearRgba::from(sprite.color)
201 };
202
203 sprite.color = new_color.into();
204 }
205}
206
207// We can restart the game by pressing "R".
208// This will trigger an [`AppState::InGame`] -> [`AppState::InGame`]
209// transition, which will run our custom schedules.
210fn trigger_game_restart(
211 input: Res<ButtonInput<KeyCode>>,
212 mut next_state: ResMut<NextState<AppState>>,
213) {
214 if input.just_pressed(KeyCode::KeyR) {
215 // Although we are already in this state setting it again will generate an identity transition.
216 // While default schedules ignore those kinds of transitions, our custom schedules will react to them.
217 next_state.set(AppState::InGame);
218 }
219}
220
221fn setup(mut commands: Commands) {
222 commands.spawn(Camera2d);
223}
224
225fn setup_game(mut commands: Commands, asset_server: Res<AssetServer>) {
226 commands.spawn(Sprite::from_image(asset_server.load("branding/icon.png")));
227 info!("Setup game");
228}
229
230fn teardown_game(mut commands: Commands, player: Single<Entity, With<Sprite>>) {
231 commands.entity(*player).despawn();
232 info!("Teardown game");
233}
More examples
- examples/ecs/generic_system.rs
- examples/games/loading_screen.rs
- examples/ecs/removal_detection.rs
- examples/async_tasks/external_source_external_thread.rs
- examples/3d/volumetric_fog.rs
- examples/asset/multi_asset_sync.rs
- examples/input/text_input.rs
- examples/ecs/one_shot_systems.rs
- examples/3d/reflection_probes.rs
- examples/window/screenshot.rs
- examples/3d/depth_of_field.rs
- examples/ui/tab_navigation.rs
- examples/ecs/observer_propagation.rs
- examples/shader/custom_shader_instancing.rs
- examples/app/log_layers_ecs.rs
- examples/3d/pbr.rs
- examples/asset/asset_decompression.rs
- examples/ecs/entity_disabling.rs
- examples/window/window_settings.rs
- examples/animation/morph_targets.rs
- examples/ecs/error_handling.rs
- examples/testbed/3d.rs
- examples/animation/animated_mesh_control.rs
- examples/games/game_menu.rs
- examples/3d/anisotropy.rs
- examples/3d/clearcoat.rs
- examples/3d/clustered_decals.rs
- examples/3d/tonemapping.rs
- examples/3d/order_independent_transparency.rs
- examples/3d/irradiance_volumes.rs
- examples/3d/shadow_caster_receiver.rs
- examples/ecs/fallible_params.rs
- examples/3d/pcss.rs
- examples/games/stepping.rs
- examples/3d/visibility_range.rs
- examples/window/custom_cursor_image.rs
- examples/3d/edit_material_on_gltf.rs
- examples/ecs/hierarchy.rs
- examples/audio/soundtrack.rs
- examples/3d/lightmaps.rs
- examples/animation/animated_mesh.rs
- examples/math/bounding_2d.rs
- examples/ecs/relationships.rs
- examples/3d/occlusion_culling.rs
- examples/animation/eased_motion.rs
- examples/games/alien_cake_addict.rs
- examples/games/breakout.rs
- examples/3d/ssr.rs
- examples/animation/animated_mesh_events.rs
- examples/window/monitor_info.rs
- examples/animation/animation_graph.rs
- examples/async_tasks/async_compute.rs
- examples/math/random_sampling.rs
- examples/stress_tests/transform_hierarchy.rs
- examples/animation/animation_masks.rs
- examples/ui/text_wrap_debug.rs
- examples/3d/deferred_rendering.rs
- examples/testbed/ui.rs
- examples/math/sampling_primitives.rs
- examples/3d/anti_aliasing.rs
- examples/3d/mixed_lighting.rs
- examples/ecs/component_hooks.rs
- examples/3d/ssao.rs
- examples/stress_tests/many_foxes.rs
- examples/3d/bloom_3d.rs
- examples/2d/bloom_2d.rs
- examples/ui/directional_navigation.rs
- examples/animation/custom_skinned_mesh.rs
- examples/animation/animated_transform.rs
- examples/3d/transmission.rs
- examples/ui/text_debug.rs
- examples/ui/borders.rs
- examples/ui/scroll.rs
Sourcepub fn get_entity(
&mut self,
entity: Entity,
) -> Result<EntityCommands<'_>, EntityDoesNotExistError>
pub fn get_entity( &mut self, entity: Entity, ) -> Result<EntityCommands<'_>, EntityDoesNotExistError>
Returns the EntityCommands
for the requested Entity
if it exists.
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 EntityDoesNotExistError
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
entity
for the infallible version.
Examples found in repository?
144fn explode_mine(trigger: Trigger<Explode>, query: Query<&Mine>, mut commands: Commands) {
145 // If a triggered event is targeting a specific entity you can access it with `.target()`
146 let id = trigger.target();
147 let Ok(mut entity) = commands.get_entity(id) else {
148 return;
149 };
150 info!("Boom! {} exploded.", id.index());
151 entity.despawn();
152 let mine = query.get(id).unwrap();
153 // Trigger another explosion cascade.
154 commands.trigger(ExplodeMines {
155 pos: mine.pos,
156 radius: mine.size,
157 });
158}
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
spawn
to spawn an entity with components.spawn_empty
to spawn an entity without components.
Examples found in repository?
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}
More examples
58fn setup(mut commands: Commands, assets: Res<AssetServer>, color_tint: Res<ColorTint>) {
59 warn!(include_str!("warning_string.txt"));
60
61 let mut rng = rand::thread_rng();
62
63 let tile_size = Vec2::splat(64.0);
64 let map_size = Vec2::splat(320.0);
65
66 let half_x = (map_size.x / 2.0) as i32;
67 let half_y = (map_size.y / 2.0) as i32;
68
69 let sprite_handle = assets.load("branding/icon.png");
70
71 // Spawns the camera
72
73 commands.spawn(Camera2d);
74
75 // Builds and spawns the sprites
76 let mut sprites = vec![];
77 for y in -half_y..half_y {
78 for x in -half_x..half_x {
79 let position = Vec2::new(x as f32, y as f32);
80 let translation = (position * tile_size).extend(rng.r#gen::<f32>());
81 let rotation = Quat::from_rotation_z(rng.r#gen::<f32>());
82 let scale = Vec3::splat(rng.r#gen::<f32>() * 2.0);
83
84 sprites.push((
85 Sprite {
86 image: sprite_handle.clone(),
87 custom_size: Some(tile_size),
88 color: if color_tint.0 {
89 COLORS[rng.gen_range(0..3)]
90 } else {
91 Color::WHITE
92 },
93 ..default()
94 },
95 Transform {
96 translation,
97 rotation,
98 scale,
99 },
100 ));
101 }
102 }
103 commands.spawn_batch(sprites);
104}
104fn setup(mut commands: Commands, font: Res<FontHandle>, args: Res<Args>) {
105 warn!(include_str!("warning_string.txt"));
106
107 let mut rng = ChaCha8Rng::seed_from_u64(42);
108
109 let tile_size = Vec2::splat(64.0);
110 let map_size = Vec2::splat(640.0);
111
112 let half_x = (map_size.x / 4.0) as i32;
113 let half_y = (map_size.y / 4.0) as i32;
114
115 // Spawns the camera
116
117 commands.spawn(Camera2d);
118
119 // Builds and spawns the `Text2d`s, distributing them in a way that ensures a
120 // good distribution of on-screen and off-screen entities.
121 let mut text2ds = vec![];
122 for y in -half_y..half_y {
123 for x in -half_x..half_x {
124 let position = Vec2::new(x as f32, y as f32);
125 let translation = (position * tile_size).extend(rng.r#gen::<f32>());
126 let rotation = Quat::from_rotation_z(rng.r#gen::<f32>());
127 let scale = Vec3::splat(rng.r#gen::<f32>() * 2.0);
128 let color = Hsla::hsl(rng.gen_range(0.0..360.0), 0.8, 0.8);
129
130 text2ds.push((
131 Text2d(random_text(&mut rng, &args)),
132 random_text_font(&mut rng, &args, font.0.clone()),
133 TextColor(color.into()),
134 TextLayout::new_with_justify(if args.center {
135 JustifyText::Center
136 } else {
137 JustifyText::Left
138 }),
139 Transform {
140 translation,
141 rotation,
142 scale,
143 },
144 ));
145 }
146 }
147
148 if args.no_frustum_culling {
149 let bundles = text2ds.into_iter().map(|bundle| (bundle, NoFrustumCulling));
150 commands.spawn_batch(bundles);
151 } else {
152 commands.spawn_batch(text2ds);
153 }
154}
44fn setup(
45 mut commands: Commands,
46 mut meshes: ResMut<Assets<Mesh>>,
47 mut materials: ResMut<Assets<StandardMaterial>>,
48) {
49 warn!(include_str!("warning_string.txt"));
50
51 const LIGHT_RADIUS: f32 = 0.3;
52 const LIGHT_INTENSITY: f32 = 1000.0;
53 const RADIUS: f32 = 50.0;
54 const N_LIGHTS: usize = 100_000;
55
56 commands.spawn((
57 Mesh3d(meshes.add(Sphere::new(RADIUS).mesh().ico(9).unwrap())),
58 MeshMaterial3d(materials.add(Color::WHITE)),
59 Transform::from_scale(Vec3::NEG_ONE),
60 ));
61
62 let mesh = meshes.add(Cuboid::default());
63 let material = materials.add(StandardMaterial {
64 base_color: DEEP_PINK.into(),
65 ..default()
66 });
67
68 // NOTE: This pattern is good for testing performance of culling as it provides roughly
69 // the same number of visible meshes regardless of the viewing angle.
70 // NOTE: f64 is used to avoid precision issues that produce visual artifacts in the distribution
71 let golden_ratio = 0.5f64 * (1.0f64 + 5.0f64.sqrt());
72
73 // Spawn N_LIGHTS many lights
74 commands.spawn_batch((0..N_LIGHTS).map(move |i| {
75 let mut rng = thread_rng();
76
77 let spherical_polar_theta_phi = fibonacci_spiral_on_sphere(golden_ratio, i, N_LIGHTS);
78 let unit_sphere_p = spherical_polar_to_cartesian(spherical_polar_theta_phi);
79
80 (
81 PointLight {
82 range: LIGHT_RADIUS,
83 intensity: LIGHT_INTENSITY,
84 color: Color::hsl(rng.gen_range(0.0..360.0), 1.0, 0.5),
85 ..default()
86 },
87 Transform::from_translation((RADIUS as f64 * unit_sphere_p).as_vec3()),
88 )
89 }));
90
91 // camera
92 match std::env::args().nth(1).as_deref() {
93 Some("orthographic") => commands.spawn((
94 Camera3d::default(),
95 Projection::from(OrthographicProjection {
96 scaling_mode: ScalingMode::FixedHorizontal {
97 viewport_width: 20.0,
98 },
99 ..OrthographicProjection::default_3d()
100 }),
101 )),
102 _ => commands.spawn(Camera3d::default()),
103 };
104
105 // add one cube, the only one with strong handles
106 // also serves as a reference point during rotation
107 commands.spawn((
108 Mesh3d(mesh),
109 MeshMaterial3d(material),
110 Transform {
111 translation: Vec3::new(0.0, RADIUS, 0.0),
112 scale: Vec3::splat(5.0),
113 ..default()
114 },
115 ));
116}
37fn setup(
38 mut commands: Commands,
39 mut meshes: ResMut<Assets<Mesh>>,
40 mut materials: ResMut<Assets<StandardMaterial>>,
41) {
42 // ground plane
43 commands.spawn((
44 Mesh3d(meshes.add(Plane3d::default().mesh().size(100.0, 100.0))),
45 MeshMaterial3d(materials.add(Color::WHITE)),
46 Movable,
47 ));
48
49 // cubes
50
51 // We're seeding the PRNG here to make this example deterministic for testing purposes.
52 // This isn't strictly required in practical use unless you need your app to be deterministic.
53 let mut rng = ChaCha8Rng::seed_from_u64(19878367467713);
54 let cube_mesh = meshes.add(Cuboid::new(0.5, 0.5, 0.5));
55 let blue = materials.add(Color::srgb_u8(124, 144, 255));
56
57 commands.spawn_batch(
58 std::iter::repeat_with(move || {
59 let x = rng.gen_range(-5.0..5.0);
60 let y = rng.gen_range(0.0..3.0);
61 let z = rng.gen_range(-5.0..5.0);
62
63 (
64 Mesh3d(cube_mesh.clone()),
65 MeshMaterial3d(blue.clone()),
66 Transform::from_xyz(x, y, z),
67 Movable,
68 )
69 })
70 .take(40),
71 );
72
73 let sphere_mesh = meshes.add(Sphere::new(0.05).mesh().uv(32, 18));
74 let sphere_mesh_direction = meshes.add(Sphere::new(0.1).mesh().uv(32, 18));
75 let red_emissive = materials.add(StandardMaterial {
76 base_color: RED.into(),
77 emissive: LinearRgba::new(1.0, 0.0, 0.0, 0.0),
78 ..default()
79 });
80 let maroon_emissive = materials.add(StandardMaterial {
81 base_color: MAROON.into(),
82 emissive: LinearRgba::new(0.369, 0.0, 0.0, 0.0),
83 ..default()
84 });
85
86 for x in 0..4 {
87 for z in 0..4 {
88 let x = x as f32 - 2.0;
89 let z = z as f32 - 2.0;
90 // red spot_light
91 commands
92 .spawn((
93 SpotLight {
94 intensity: 40_000.0, // lumens
95 color: Color::WHITE,
96 shadows_enabled: true,
97 inner_angle: PI / 4.0 * 0.85,
98 outer_angle: PI / 4.0,
99 ..default()
100 },
101 Transform::from_xyz(1.0 + x, 2.0, z)
102 .looking_at(Vec3::new(1.0 + x, 0.0, z), Vec3::X),
103 ))
104 .with_children(|builder| {
105 builder.spawn((
106 Mesh3d(sphere_mesh.clone()),
107 MeshMaterial3d(red_emissive.clone()),
108 ));
109 builder.spawn((
110 Mesh3d(sphere_mesh_direction.clone()),
111 MeshMaterial3d(maroon_emissive.clone()),
112 Transform::from_translation(Vec3::Z * -0.1),
113 NotShadowCaster,
114 ));
115 });
116 }
117 }
118
119 // camera
120 commands.spawn((
121 Camera3d::default(),
122 Camera {
123 hdr: true,
124 ..default()
125 },
126 Transform::from_xyz(-4.0, 5.0, 10.0).looking_at(Vec3::ZERO, Vec3::Y),
127 ));
128
129 commands.spawn((
130 Text::new(INSTRUCTIONS),
131 Node {
132 position_type: PositionType::Absolute,
133 top: Val::Px(12.0),
134 left: Val::Px(12.0),
135 ..default()
136 },
137 ));
138}
392fn spawn_birds(
393 commands: &mut Commands,
394 args: &Args,
395 primary_window_resolution: &WindowResolution,
396 counter: &mut BevyCounter,
397 spawn_count: usize,
398 bird_resources: &mut BirdResources,
399 waves_to_simulate: Option<usize>,
400 wave: usize,
401) {
402 let bird_x = (primary_window_resolution.width() / -2.) + HALF_BIRD_SIZE;
403 let bird_y = (primary_window_resolution.height() / 2.) - HALF_BIRD_SIZE;
404
405 let half_extents = 0.5 * primary_window_resolution.size();
406
407 let color = counter.color;
408 let current_count = counter.count;
409
410 match args.mode {
411 Mode::Sprite => {
412 let batch = (0..spawn_count)
413 .map(|count| {
414 let bird_z = if args.ordered_z {
415 (current_count + count) as f32 * 0.00001
416 } else {
417 bird_resources.transform_rng.r#gen::<f32>()
418 };
419
420 let (transform, velocity) = bird_velocity_transform(
421 half_extents,
422 Vec3::new(bird_x, bird_y, bird_z),
423 &mut bird_resources.velocity_rng,
424 waves_to_simulate,
425 FIXED_DELTA_TIME,
426 );
427
428 let color = if args.vary_per_instance {
429 Color::linear_rgb(
430 bird_resources.color_rng.r#gen(),
431 bird_resources.color_rng.r#gen(),
432 bird_resources.color_rng.r#gen(),
433 )
434 } else {
435 color
436 };
437 (
438 Sprite {
439 image: bird_resources
440 .textures
441 .choose(&mut bird_resources.material_rng)
442 .unwrap()
443 .clone(),
444 color,
445 ..default()
446 },
447 transform,
448 Bird { velocity },
449 )
450 })
451 .collect::<Vec<_>>();
452 commands.spawn_batch(batch);
453 }
454 Mode::Mesh2d => {
455 let batch = (0..spawn_count)
456 .map(|count| {
457 let bird_z = if args.ordered_z {
458 (current_count + count) as f32 * 0.00001
459 } else {
460 bird_resources.transform_rng.r#gen::<f32>()
461 };
462
463 let (transform, velocity) = bird_velocity_transform(
464 half_extents,
465 Vec3::new(bird_x, bird_y, bird_z),
466 &mut bird_resources.velocity_rng,
467 waves_to_simulate,
468 FIXED_DELTA_TIME,
469 );
470
471 let material =
472 if args.vary_per_instance || args.material_texture_count > args.waves {
473 bird_resources
474 .materials
475 .choose(&mut bird_resources.material_rng)
476 .unwrap()
477 .clone()
478 } else {
479 bird_resources.materials[wave % bird_resources.materials.len()].clone()
480 };
481 (
482 Mesh2d(bird_resources.quad.clone()),
483 MeshMaterial2d(material),
484 transform,
485 Bird { velocity },
486 )
487 })
488 .collect::<Vec<_>>();
489 commands.spawn_batch(batch);
490 }
491 }
492
493 counter.count += spawn_count;
494 counter.color = Color::linear_rgb(
495 bird_resources.color_rng.r#gen(),
496 bird_resources.color_rng.r#gen(),
497 bird_resources.color_rng.r#gen(),
498 );
499}
Sourcepub fn queue<C, T>(&mut self, command: C)where
C: Command<T> + HandleError<T>,
pub fn queue<C, T>(&mut self, command: C)where
C: Command<T> + HandleError<T>,
Pushes a generic Command
to the command queue.
If the Command
returns a Result
,
it will be handled using the default 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
command
module.
§Example
#[derive(Resource, Default)]
struct Counter(u64);
struct AddToCounter(String);
impl Command<Result> for AddToCounter {
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;
});
}
Sourcepub fn queue_handled<C, T>(
&mut self,
command: C,
error_handler: fn(BevyError, ErrorContext),
)where
C: Command<T> + HandleError<T>,
pub fn queue_handled<C, T>(
&mut self,
command: C,
error_handler: fn(BevyError, ErrorContext),
)where
C: Command<T> + HandleError<T>,
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 default 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
command
module.
§Example
use bevy_ecs::error::warn;
#[derive(Resource, Default)]
struct Counter(u64);
struct AddToCounter(String);
impl Command<Result> for AddToCounter {
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?
169fn failing_commands(mut commands: Commands) {
170 commands
171 // This entity doesn't exist!
172 .entity(Entity::from_raw(12345678))
173 // Normally, this failed command would panic,
174 // but since we've set the global error handler to `warn`
175 // it will log a warning instead.
176 .insert(Transform::default());
177
178 // The error handlers for commands can be set individually as well,
179 // by using the queue_handled method.
180 commands.queue_handled(
181 |world: &mut World| -> Result {
182 world
183 .get_resource::<UninitializedResource>()
184 .ok_or("Resource not initialized when accessed in a command")?;
185
186 Ok(())
187 },
188 |error, context| {
189 error!("{error}, {context}");
190 },
191 );
192}
Sourcepub fn insert_or_spawn_batch<I, B>(&mut self, bundles_iter: I)where
I: IntoIterator<Item = (Entity, B)> + Send + Sync + 'static,
B: Bundle,
<B as DynamicBundle>::Effect: NoBundleEffect,
👎Deprecated since 0.16.0: This can cause extreme performance problems when used with lots of arbitrary free entities. See #18054 on GitHub.
pub fn insert_or_spawn_batch<I, B>(&mut self, bundles_iter: I)where
I: IntoIterator<Item = (Entity, B)> + Send + Sync + 'static,
B: Bundle,
<B as DynamicBundle>::Effect: NoBundleEffect,
Pushes a Command
to the queue for creating entities, if needed,
and for adding a bundle to each entity.
bundles_iter
is a type that can be converted into an (Entity
, Bundle
) iterator
(it can also be a collection).
When the command is applied,
for each (Entity
, Bundle
) pair in the given bundles_iter
,
the Entity
is spawned, if it does not exist already.
Then, the Bundle
is added to the entity.
This method is equivalent to iterating bundles_iter
,
calling spawn
for each bundle,
and passing it to insert
,
but it is faster due to memory pre-allocation.
§Note
Spawning a specific entity
value is rarely the right choice. Most apps should use Commands::spawn_batch
.
This method should generally only be used for sharing entities across apps, and only when they have a scheme
worked out to share an ID space (which doesn’t happen by default).
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 default 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 default 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?
328pub fn extract_colored_mesh2d(
329 mut commands: Commands,
330 mut previous_len: Local<usize>,
331 // When extracting, you must use `Extract` to mark the `SystemParam`s
332 // which should be taken from the main world.
333 query: Extract<
334 Query<
335 (
336 Entity,
337 RenderEntity,
338 &ViewVisibility,
339 &GlobalTransform,
340 &Mesh2d,
341 ),
342 With<ColoredMesh2d>,
343 >,
344 >,
345 mut render_mesh_instances: ResMut<RenderColoredMesh2dInstances>,
346) {
347 let mut values = Vec::with_capacity(*previous_len);
348 for (entity, render_entity, view_visibility, transform, handle) in &query {
349 if !view_visibility.get() {
350 continue;
351 }
352
353 let transforms = Mesh2dTransforms {
354 world_from_local: (&transform.affine()).into(),
355 flags: MeshFlags::empty().bits(),
356 };
357
358 values.push((render_entity, ColoredMesh2d));
359 render_mesh_instances.insert(
360 entity.into(),
361 RenderMesh2dInstance {
362 mesh_asset_id: handle.0.id(),
363 transforms,
364 material_bind_group_id: Material2dBindGroupId::default(),
365 automatic_batching: false,
366 tag: 0,
367 },
368 );
369 }
370 *previous_len = values.len();
371 commands.try_insert_batch(values);
372}
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
32fn setup_scene(
33 mut commands: Commands,
34 mut meshes: ResMut<Assets<Mesh>>,
35 mut materials: ResMut<Assets<ColorMaterial>>,
36) {
37 // World where we move the player
38 commands.spawn((
39 Mesh2d(meshes.add(Rectangle::new(1000., 700.))),
40 MeshMaterial2d(materials.add(Color::srgb(0.2, 0.2, 0.3))),
41 ));
42
43 // Player
44 commands.spawn((
45 Player,
46 Mesh2d(meshes.add(Rectangle::new(50.0, 100.0))), // Rectangle size (width, height)
47 MeshMaterial2d(materials.add(Color::srgb(0.25, 0.94, 0.91))), // RGB values must be in range 0.0 to 1.0
48 Transform::from_xyz(0., 0., 2.),
49 ));
50
51 commands.spawn((
52 Mesh2d(meshes.add(Rectangle::new(50.0, 50.0))), // Rectangle size (width, height)
53 MeshMaterial2d(materials.add(Color::srgb(0.85, 0.0, 0.2))), // RGB values must be in range 0.0 to 1.0
54 Transform::from_xyz(-450.0, 200.0, 2.),
55 ));
56
57 commands.spawn((
58 Mesh2d(meshes.add(Rectangle::new(70.0, 50.0))), // Rectangle size (width, height)
59 MeshMaterial2d(materials.add(Color::srgb(0.5, 0.8, 0.2))), // RGB values must be in range 0.0 to 1.0
60 Transform::from_xyz(450.0, -150.0, 2.),
61 ));
62 commands.init_resource::<ScreenShake>();
63}
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
- examples/2d/sprite_tile.rs
- examples/shader/array_texture.rs
- examples/window/window_settings.rs
- examples/audio/soundtrack.rs
- examples/games/desk_toy.rs
- examples/async_tasks/external_source_external_thread.rs
- examples/games/loading_screen.rs
- examples/ecs/ecs_guide.rs
- examples/animation/morph_targets.rs
- examples/games/game_menu.rs
- examples/shader/compute_shader_game_of_life.rs
- examples/remote/server.rs
- examples/ui/font_atlas_debug.rs
- examples/3d/skybox.rs
- examples/asset/multi_asset_sync.rs
- examples/testbed/3d.rs
- examples/state/custom_transitions.rs
- examples/state/states.rs
- examples/state/sub_states.rs
- examples/shader/storage_buffer.rs
- examples/movement/smooth_follow.rs
- examples/games/contributors.rs
- examples/gizmos/axes.rs
- examples/3d/motion_blur.rs
- examples/animation/animation_graph.rs
- examples/animation/animated_mesh_events.rs
- examples/math/cubic_splines.rs
- examples/2d/cpu_draw.rs
- examples/animation/animated_mesh_control.rs
- examples/transforms/align.rs
- examples/math/random_sampling.rs
- examples/shader/gpu_readback.rs
- examples/state/computed_states.rs
- examples/animation/animation_masks.rs
- examples/games/alien_cake_addict.rs
- examples/3d/auto_exposure.rs
- examples/stress_tests/bevymark.rs
- examples/games/breakout.rs
- examples/stress_tests/many_foxes.rs
- examples/math/sampling_primitives.rs
- examples/3d/lighting.rs
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: SystemId)
pub fn run_system(&mut self, id: SystemId)
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
97fn level_selection(
98 mut commands: Commands,
99 keyboard: Res<ButtonInput<KeyCode>>,
100 level_data: Res<LevelData>,
101 loading_state: Res<LoadingState>,
102) {
103 // Only trigger a load if the current level is fully loaded.
104 if let LoadingState::LevelReady = loading_state.as_ref() {
105 if keyboard.just_pressed(KeyCode::Digit1) {
106 commands.run_system(level_data.unload_level_id);
107 commands.run_system(level_data.level_1_id);
108 } else if keyboard.just_pressed(KeyCode::Digit2) {
109 commands.run_system(level_data.unload_level_id);
110 commands.run_system(level_data.level_2_id);
111 }
112 }
113}
Sourcepub fn run_system_with<I>(
&mut self,
id: SystemId<I>,
input: <I as SystemInput>::Inner<'static>,
)
pub fn run_system_with<I>( &mut self, id: SystemId<I>, 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
71fn setup(mut commands: Commands) {
72 let level_data = LevelData {
73 unload_level_id: commands.register_system(unload_current_level),
74 level_1_id: commands.register_system(load_level_1),
75 level_2_id: commands.register_system(load_level_2),
76 };
77 commands.insert_resource(level_data);
78
79 // Spawns the UI that will show the user prompts.
80 let text_style = TextFont {
81 font_size: 42.0,
82 ..default()
83 };
84 commands
85 .spawn((
86 Node {
87 justify_self: JustifySelf::Center,
88 align_self: AlignSelf::FlexEnd,
89 ..default()
90 },
91 BackgroundColor(Color::NONE),
92 ))
93 .with_child((Text::new("Press 1 or 2 to load a new scene."), text_style));
94}
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.
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(&mut self, event: impl Event)
pub fn trigger(&mut self, event: impl Event)
Sends a “global” Trigger
without any targets.
This will run any Observer
of the given Event
that isn’t scoped to specific targets.
Examples found in repository?
144fn explode_mine(trigger: Trigger<Explode>, query: Query<&Mine>, mut commands: Commands) {
145 // If a triggered event is targeting a specific entity you can access it with `.target()`
146 let id = trigger.target();
147 let Ok(mut entity) = commands.get_entity(id) else {
148 return;
149 };
150 info!("Boom! {} exploded.", id.index());
151 entity.despawn();
152 let mine = query.get(id).unwrap();
153 // Trigger another explosion cascade.
154 commands.trigger(ExplodeMines {
155 pos: mine.pos,
156 radius: mine.size,
157 });
158}
159
160// Draw a circle for each mine using `Gizmos`
161fn draw_shapes(mut gizmos: Gizmos, mines: Query<&Mine>) {
162 for mine in &mines {
163 gizmos.circle_2d(
164 mine.pos,
165 mine.size,
166 Color::hsl((mine.size - 4.0) / 16.0 * 360.0, 1.0, 0.8),
167 );
168 }
169}
170
171// Trigger `ExplodeMines` at the position of a given click
172fn handle_click(
173 mouse_button_input: Res<ButtonInput<MouseButton>>,
174 camera: Single<(&Camera, &GlobalTransform)>,
175 windows: Query<&Window>,
176 mut commands: Commands,
177) {
178 let Ok(windows) = windows.single() else {
179 return;
180 };
181
182 let (camera, camera_transform) = *camera;
183 if let Some(pos) = windows
184 .cursor_position()
185 .and_then(|cursor| camera.viewport_to_world(camera_transform, cursor).ok())
186 .map(|ray| ray.origin.truncate())
187 {
188 if mouse_button_input.just_pressed(MouseButton::Left) {
189 commands.trigger(ExplodeMines { pos, radius: 1.0 });
190 }
191 }
192}
Sourcepub fn trigger_targets(
&mut self,
event: impl Event,
targets: impl TriggerTargets + Send + Sync + 'static,
)
pub fn trigger_targets( &mut self, event: impl Event, targets: impl TriggerTargets + Send + Sync + 'static, )
Sends a Trigger
for the given targets.
This will run any Observer
of the given Event
watching those targets.
Examples found in repository?
More examples
10fn main() {
11 App::new()
12 .add_plugins(DefaultPlugins)
13 .init_resource::<SpatialIndex>()
14 .add_systems(Startup, setup)
15 .add_systems(Update, (draw_shapes, handle_click))
16 // Observers are systems that run when an event is "triggered". This observer runs whenever
17 // `ExplodeMines` is triggered.
18 .add_observer(
19 |trigger: Trigger<ExplodeMines>,
20 mines: Query<&Mine>,
21 index: Res<SpatialIndex>,
22 mut commands: Commands| {
23 // You can access the trigger data via the `Observer`
24 let event = trigger.event();
25 // Access resources
26 for e in index.get_nearby(event.pos) {
27 // Run queries
28 let mine = mines.get(e).unwrap();
29 if mine.pos.distance(event.pos) < mine.size + event.radius {
30 // And queue commands, including triggering additional events
31 // Here we trigger the `Explode` event for entity `e`
32 commands.trigger_targets(Explode, e);
33 }
34 }
35 },
36 )
37 // This observer runs whenever the `Mine` component is added to an entity, and places it in a simple spatial index.
38 .add_observer(on_add_mine)
39 // This observer runs whenever the `Mine` component is removed from an entity (including despawning it)
40 // and removes it from the spatial index.
41 .add_observer(on_remove_mine)
42 .run();
43}
373fn interact_with_focused_button(
374 action_state: Res<ActionState>,
375 input_focus: Res<InputFocus>,
376 mut commands: Commands,
377) {
378 if action_state
379 .pressed_actions
380 .contains(&DirectionalNavigationAction::Select)
381 {
382 if let Some(focused_entity) = input_focus.0 {
383 commands.trigger_targets(
384 Pointer::<Click> {
385 target: focused_entity,
386 // We're pretending that we're a mouse
387 pointer_id: PointerId::Mouse,
388 // This field isn't used, so we're just setting it to a placeholder value
389 pointer_location: Location {
390 target: NormalizedRenderTarget::Image(
391 bevy_render::camera::ImageRenderTarget {
392 handle: Handle::default(),
393 scale_factor: FloatOrd(1.0),
394 },
395 ),
396 position: Vec2::ZERO,
397 },
398 event: Click {
399 button: PointerButton::Primary,
400 // This field isn't used, so we're just setting it to a placeholder value
401 hit: HitData {
402 camera: Entity::PLACEHOLDER,
403 depth: 0.0,
404 position: None,
405 normal: None,
406 },
407 duration: Duration::from_secs_f32(0.1),
408 },
409 },
410 focused_entity,
411 );
412 }
413 }
414}
Sourcepub fn add_observer<E, B, M>(
&mut self,
observer: impl IntoObserverSystem<E, B, M>,
) -> EntityCommands<'_>
pub fn add_observer<E, B, M>( &mut self, observer: impl IntoObserverSystem<E, B, M>, ) -> EntityCommands<'_>
Spawns an Observer
and returns the EntityCommands
associated
with the entity that stores the observer.
Calling observe
on the returned
EntityCommands
will observe the observer itself, which you very
likely do not want.
Sourcepub fn send_event<E>(&mut self, event: E) -> &mut Commands<'w, 's>where
E: Event,
pub fn send_event<E>(&mut self, event: E) -> &mut Commands<'w, 's>where
E: Event,
Sends an arbitrary Event
.
This is a convenience method for sending events
without requiring an EventWriter
.
§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 events are performance-critical or very frequently sent,
consider using a typed EventWriter
instead.
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 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§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,
system_meta: &mut SystemMeta,
) -> <Commands<'_, '_> as SystemParam>::State
fn init_state( world: &mut World, system_meta: &mut SystemMeta, ) -> <Commands<'_, '_> as SystemParam>::State
World
access used by this SystemParam
and creates a new instance of this param’s State
.Source§unsafe fn new_archetype(
state: &mut <Commands<'_, '_> as SystemParam>::State,
archetype: &Archetype,
system_meta: &mut SystemMeta,
)
unsafe fn new_archetype( state: &mut <Commands<'_, '_> as SystemParam>::State, archetype: &Archetype, system_meta: &mut SystemMeta, )
Archetype
, registers the components accessed by this SystemParam
(if applicable).a Read moreSource§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 validate_param(
state: &<Commands<'_, '_> as SystemParam>::State,
system_meta: &SystemMeta,
world: UnsafeWorldCell<'_>,
) -> Result<(), SystemParamValidationError>
unsafe fn validate_param( state: &<Commands<'_, '_> as SystemParam>::State, system_meta: &SystemMeta, world: UnsafeWorldCell<'_>, ) -> Result<(), SystemParamValidationError>
Source§unsafe fn get_param<'w, 's>(
state: &'s mut <Commands<'_, '_> as SystemParam>::State,
system_meta: &SystemMeta,
world: UnsafeWorldCell<'w>,
change_tick: Tick,
) -> <Commands<'_, '_> as SystemParam>::Item<'w, 's>
unsafe fn get_param<'w, 's>( state: &'s mut <Commands<'_, '_> as SystemParam>::State, system_meta: &SystemMeta, world: UnsafeWorldCell<'w>, change_tick: Tick, ) -> <Commands<'_, '_> as SystemParam>::Item<'w, 's>
SystemParamFunction
. Read moreimpl<'w, 's> ReadOnlySystemParam for Commands<'w, 's>
impl Send for Commands<'_, '_>
impl Sync for Commands<'_, '_>
Auto Trait Implementations§
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> !UnwindSafe 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
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
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> 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<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.Source§impl<T> Pointable for T
impl<T> Pointable for T
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.