Struct EntityCommands

Source
pub struct EntityCommands<'a> { /* private fields */ }
Expand description

A list of commands that will be run to modify an Entity.

§Note

Most Commands (and thereby EntityCommands) are deferred: when you call the command, if it requires mutable access to the World (that is, if it removes, adds, or changes something), it’s not executed immediately.

Instead, the command is added to a “command queue.” The command queue is applied later when the ApplyDeferred system runs. Commands are executed one-by-one so that each command can have exclusive access to the World.

§Fallible

Due to their deferred nature, an entity you’re trying to change with an EntityCommand can be despawned by the time the command is executed.

All deferred entity commands will check whether the entity exists at the time of execution and will return an error if it doesn’t.

§Error handling

An EntityCommand 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 EntityCommands::queue_handled.

The error module provides some simple error handlers for convenience.

Implementations§

Source§

impl<'a> EntityCommands<'a>

Source

pub fn with_children( &mut self, func: impl FnOnce(&mut RelatedSpawnerCommands<'_, ChildOf>), ) -> &mut EntityCommands<'a>

Spawns children of this entity (with a ChildOf relationship) by taking a function that operates on a ChildSpawner.

Examples found in repository?
examples/ecs/observer_propagation.rs (lines 31-41)
27fn setup(mut commands: Commands) {
28    commands
29        .spawn((Name::new("Goblin"), HitPoints(50)))
30        .observe(take_damage)
31        .with_children(|parent| {
32            parent
33                .spawn((Name::new("Helmet"), Armor(5)))
34                .observe(block_attack);
35            parent
36                .spawn((Name::new("Socks"), Armor(10)))
37                .observe(block_attack);
38            parent
39                .spawn((Name::new("Shirt"), Armor(15)))
40                .observe(block_attack);
41        });
42}
More examples
Hide additional examples
examples/3d/mixed_lighting.rs (lines 187-198)
184fn spawn_buttons(commands: &mut Commands) {
185    commands
186        .spawn(widgets::main_ui_node())
187        .with_children(|parent| {
188            widgets::spawn_option_buttons(
189                parent,
190                "Lighting",
191                &[
192                    (LightingMode::Baked, "Baked"),
193                    (LightingMode::MixedDirect, "Mixed (Direct)"),
194                    (LightingMode::MixedIndirect, "Mixed (Indirect)"),
195                    (LightingMode::RealTime, "Real-Time"),
196                ],
197            );
198        });
199}
examples/app/log_layers_ecs.rs (lines 149-159)
142fn print_logs(
143    mut events: EventReader<LogEvent>,
144    mut commands: Commands,
145    log_viewer_root: Single<Entity, With<LogViewerRoot>>,
146) {
147    let root_entity = *log_viewer_root;
148
149    commands.entity(root_entity).with_children(|child| {
150        for event in events.read() {
151            child.spawn(Text::default()).with_children(|child| {
152                child.spawn((
153                    TextSpan::new(format!("{:5} ", event.level)),
154                    TextColor(level_color(&event.level)),
155                ));
156                child.spawn(TextSpan::new(&event.message));
157            });
158        }
159    });
160}
examples/ecs/one_shot_systems.rs (lines 104-111)
92fn setup_ui(mut commands: Commands) {
93    commands.spawn(Camera2d);
94    commands
95        .spawn((
96            Text::default(),
97            TextLayout::new_with_justify(JustifyText::Center),
98            Node {
99                align_self: AlignSelf::Center,
100                justify_self: JustifySelf::Center,
101                ..default()
102            },
103        ))
104        .with_children(|p| {
105            p.spawn(TextSpan::new("Press A or B to trigger a one-shot system\n"));
106            p.spawn(TextSpan::new("Last Triggered: "));
107            p.spawn((
108                TextSpan::new("-"),
109                TextColor(bevy::color::palettes::css::ORANGE.into()),
110            ));
111        });
112}
examples/3d/color_grading.rs (lines 149-161)
138fn add_buttons(commands: &mut Commands, font: &Handle<Font>, color_grading: &ColorGrading) {
139    // Spawn the parent node that contains all the buttons.
140    commands
141        .spawn(Node {
142            flex_direction: FlexDirection::Column,
143            position_type: PositionType::Absolute,
144            row_gap: Val::Px(6.0),
145            left: Val::Px(12.0),
146            bottom: Val::Px(12.0),
147            ..default()
148        })
149        .with_children(|parent| {
150            // Create the first row, which contains the global controls.
151            add_buttons_for_global_controls(parent, color_grading, font);
152
153            // Create the rows for individual controls.
154            for section in [
155                SelectedColorGradingSection::Highlights,
156                SelectedColorGradingSection::Midtones,
157                SelectedColorGradingSection::Shadows,
158            ] {
159                add_buttons_for_section(parent, section, color_grading, font);
160            }
161        });
162}
163
164/// Adds the buttons for the global controls (those that control the scene as a
165/// whole as opposed to shadows, midtones, or highlights).
166fn add_buttons_for_global_controls(
167    parent: &mut ChildSpawnerCommands,
168    color_grading: &ColorGrading,
169    font: &Handle<Font>,
170) {
171    // Add the parent node for the row.
172    parent.spawn(Node::default()).with_children(|parent| {
173        // Add some placeholder text to fill this column.
174        parent.spawn(Node {
175            width: Val::Px(125.0),
176            ..default()
177        });
178
179        // Add each global color grading option button.
180        for option in [
181            SelectedGlobalColorGradingOption::Exposure,
182            SelectedGlobalColorGradingOption::Temperature,
183            SelectedGlobalColorGradingOption::Tint,
184            SelectedGlobalColorGradingOption::Hue,
185        ] {
186            add_button_for_value(
187                parent,
188                SelectedColorGradingOption::Global(option),
189                color_grading,
190                font,
191            );
192        }
193    });
194}
195
196/// Adds the buttons that control color grading for individual sections
197/// (highlights, midtones, shadows).
198fn add_buttons_for_section(
199    parent: &mut ChildSpawnerCommands,
200    section: SelectedColorGradingSection,
201    color_grading: &ColorGrading,
202    font: &Handle<Font>,
203) {
204    // Spawn the row container.
205    parent
206        .spawn(Node {
207            align_items: AlignItems::Center,
208            ..default()
209        })
210        .with_children(|parent| {
211            // Spawn the label ("Highlights", etc.)
212            add_text(parent, &section.to_string(), font, Color::WHITE).insert(Node {
213                width: Val::Px(125.0),
214                ..default()
215            });
216
217            // Spawn the buttons.
218            for option in [
219                SelectedSectionColorGradingOption::Saturation,
220                SelectedSectionColorGradingOption::Contrast,
221                SelectedSectionColorGradingOption::Gamma,
222                SelectedSectionColorGradingOption::Gain,
223                SelectedSectionColorGradingOption::Lift,
224            ] {
225                add_button_for_value(
226                    parent,
227                    SelectedColorGradingOption::Section(section, option),
228                    color_grading,
229                    font,
230                );
231            }
232        });
233}
234
235/// Adds a button that controls one of the color grading values.
236fn add_button_for_value(
237    parent: &mut ChildSpawnerCommands,
238    option: SelectedColorGradingOption,
239    color_grading: &ColorGrading,
240    font: &Handle<Font>,
241) {
242    // Add the button node.
243    parent
244        .spawn((
245            Button,
246            Node {
247                border: UiRect::all(Val::Px(1.0)),
248                width: Val::Px(200.0),
249                justify_content: JustifyContent::Center,
250                align_items: AlignItems::Center,
251                padding: UiRect::axes(Val::Px(12.0), Val::Px(6.0)),
252                margin: UiRect::right(Val::Px(12.0)),
253                ..default()
254            },
255            BorderColor(Color::WHITE),
256            BorderRadius::MAX,
257            BackgroundColor(Color::BLACK),
258        ))
259        .insert(ColorGradingOptionWidget {
260            widget_type: ColorGradingOptionWidgetType::Button,
261            option,
262        })
263        .with_children(|parent| {
264            // Add the button label.
265            let label = match option {
266                SelectedColorGradingOption::Global(option) => option.to_string(),
267                SelectedColorGradingOption::Section(_, option) => option.to_string(),
268            };
269            add_text(parent, &label, font, Color::WHITE).insert(ColorGradingOptionWidget {
270                widget_type: ColorGradingOptionWidgetType::Label,
271                option,
272            });
273
274            // Add a spacer.
275            parent.spawn(Node {
276                flex_grow: 1.0,
277                ..default()
278            });
279
280            // Add the value text.
281            add_text(
282                parent,
283                &format!("{:.3}", option.get(color_grading)),
284                font,
285                Color::WHITE,
286            )
287            .insert(ColorGradingOptionWidget {
288                widget_type: ColorGradingOptionWidgetType::Value,
289                option,
290            });
291        });
292}
examples/ui/font_atlas_debug.rs (lines 98-108)
85fn setup(mut commands: Commands, asset_server: Res<AssetServer>, mut state: ResMut<State>) {
86    let font_handle = asset_server.load("fonts/FiraSans-Bold.ttf");
87    state.handle = font_handle.clone();
88    commands.spawn(Camera2d);
89    commands
90        .spawn((
91            Node {
92                position_type: PositionType::Absolute,
93                bottom: Val::ZERO,
94                ..default()
95            },
96            BackgroundColor(Color::NONE),
97        ))
98        .with_children(|parent| {
99            parent.spawn((
100                Text::new("a"),
101                TextFont {
102                    font: font_handle,
103                    font_size: 50.0,
104                    ..default()
105                },
106                TextColor(YELLOW.into()),
107            ));
108        });
109    // We're seeding the PRNG here to make this example deterministic for testing purposes.
110    // This isn't strictly required in practical use unless you need your app to be deterministic.
111    commands.insert_resource(SeededRng(ChaCha8Rng::seed_from_u64(19878367467713)));
112}
Source

pub fn add_children(&mut self, children: &[Entity]) -> &mut EntityCommands<'a>

Adds the given children to this entity

Examples found in repository?
examples/ui/directional_navigation.rs (line 156)
103fn setup_ui(
104    mut commands: Commands,
105    mut directional_nav_map: ResMut<DirectionalNavigationMap>,
106    mut input_focus: ResMut<InputFocus>,
107) {
108    const N_ROWS: u16 = 5;
109    const N_COLS: u16 = 3;
110
111    // Rendering UI elements requires a camera
112    commands.spawn(Camera2d);
113
114    // Create a full-screen background node
115    let root_node = commands
116        .spawn(Node {
117            width: Val::Percent(100.0),
118            height: Val::Percent(100.0),
119            ..default()
120        })
121        .id();
122
123    // Add instruction to the left of the grid
124    let instructions = commands
125        .spawn((
126            Text::new("Use arrow keys or D-pad to navigate. \
127            Click the buttons, or press Enter / the South gamepad button to interact with the focused button."),
128            Node {
129                width: Val::Px(300.0),
130                justify_content: JustifyContent::Center,
131                align_items: AlignItems::Center,
132                margin: UiRect::all(Val::Px(12.0)),
133                ..default()
134            },
135        ))
136        .id();
137
138    // Set up the root entity to hold the grid
139    let grid_root_entity = commands
140        .spawn(Node {
141            display: Display::Grid,
142            // Allow the grid to take up the full height and the rest of the width of the window
143            width: Val::Percent(100.),
144            height: Val::Percent(100.),
145            // Set the number of rows and columns in the grid
146            // allowing the grid to automatically size the cells
147            grid_template_columns: RepeatedGridTrack::auto(N_COLS),
148            grid_template_rows: RepeatedGridTrack::auto(N_ROWS),
149            ..default()
150        })
151        .id();
152
153    // Add the instructions and grid to the root node
154    commands
155        .entity(root_node)
156        .add_children(&[instructions, grid_root_entity]);
157
158    let mut button_entities: HashMap<(u16, u16), Entity> = HashMap::default();
159    for row in 0..N_ROWS {
160        for col in 0..N_COLS {
161            let button_name = format!("Button {}-{}", row, col);
162
163            let button_entity = commands
164                .spawn((
165                    Button,
166                    Node {
167                        width: Val::Px(200.0),
168                        height: Val::Px(120.0),
169                        // Add a border so we can show which element is focused
170                        border: UiRect::all(Val::Px(4.0)),
171                        // Center the button's text label
172                        justify_content: JustifyContent::Center,
173                        align_items: AlignItems::Center,
174                        // Center the button within the grid cell
175                        align_self: AlignSelf::Center,
176                        justify_self: JustifySelf::Center,
177                        ..default()
178                    },
179                    ResetTimer::default(),
180                    BorderRadius::all(Val::Px(16.0)),
181                    BackgroundColor::from(NORMAL_BUTTON),
182                    Name::new(button_name.clone()),
183                ))
184                // Add a text element to the button
185                .with_child((
186                    Text::new(button_name),
187                    // And center the text if it flows onto multiple lines
188                    TextLayout {
189                        justify: JustifyText::Center,
190                        ..default()
191                    },
192                ))
193                .id();
194
195            // Add the button to the grid
196            commands.entity(grid_root_entity).add_child(button_entity);
197
198            // Keep track of the button entities so we can set up our navigation graph
199            button_entities.insert((row, col), button_entity);
200        }
201    }
202
203    // Connect all of the buttons in the same row to each other,
204    // looping around when the edge is reached.
205    for row in 0..N_ROWS {
206        let entities_in_row: Vec<Entity> = (0..N_COLS)
207            .map(|col| button_entities.get(&(row, col)).unwrap())
208            .copied()
209            .collect();
210        directional_nav_map.add_looping_edges(&entities_in_row, CompassOctant::East);
211    }
212
213    // Connect all of the buttons in the same column to each other,
214    // but don't loop around when the edge is reached.
215    // While looping is a very reasonable choice, we're not doing it here to demonstrate the different options.
216    for col in 0..N_COLS {
217        let entities_in_column: Vec<Entity> = (0..N_ROWS)
218            .map(|row| button_entities.get(&(row, col)).unwrap())
219            .copied()
220            .collect();
221
222        directional_nav_map.add_edges(&entities_in_column, CompassOctant::South);
223    }
224
225    // When changing scenes, remember to set an initial focus!
226    let top_left_entity = *button_entities.get(&(0, 0)).unwrap();
227    input_focus.set(top_left_entity);
228}
More examples
Hide additional examples
examples/animation/custom_skinned_mesh.rs (line 162)
39fn setup(
40    mut commands: Commands,
41    asset_server: Res<AssetServer>,
42    mut meshes: ResMut<Assets<Mesh>>,
43    mut materials: ResMut<Assets<StandardMaterial>>,
44    mut skinned_mesh_inverse_bindposes_assets: ResMut<Assets<SkinnedMeshInverseBindposes>>,
45) {
46    // Create a camera
47    commands.spawn((
48        Camera3d::default(),
49        Transform::from_xyz(2.5, 2.5, 9.0).looking_at(Vec3::ZERO, Vec3::Y),
50    ));
51
52    // Create inverse bindpose matrices for a skeleton consists of 2 joints
53    let inverse_bindposes = skinned_mesh_inverse_bindposes_assets.add(vec![
54        Mat4::from_translation(Vec3::new(-0.5, -1.0, 0.0)),
55        Mat4::from_translation(Vec3::new(-0.5, -1.0, 0.0)),
56    ]);
57
58    // Create a mesh
59    let mesh = Mesh::new(
60        PrimitiveTopology::TriangleList,
61        RenderAssetUsages::RENDER_WORLD,
62    )
63    // Set mesh vertex positions
64    .with_inserted_attribute(
65        Mesh::ATTRIBUTE_POSITION,
66        vec![
67            [0.0, 0.0, 0.0],
68            [1.0, 0.0, 0.0],
69            [0.0, 0.5, 0.0],
70            [1.0, 0.5, 0.0],
71            [0.0, 1.0, 0.0],
72            [1.0, 1.0, 0.0],
73            [0.0, 1.5, 0.0],
74            [1.0, 1.5, 0.0],
75            [0.0, 2.0, 0.0],
76            [1.0, 2.0, 0.0],
77        ],
78    )
79    // Add UV coordinates that map the left half of the texture since its a 1 x
80    // 2 rectangle.
81    .with_inserted_attribute(
82        Mesh::ATTRIBUTE_UV_0,
83        vec![
84            [0.0, 0.00],
85            [0.5, 0.00],
86            [0.0, 0.25],
87            [0.5, 0.25],
88            [0.0, 0.50],
89            [0.5, 0.50],
90            [0.0, 0.75],
91            [0.5, 0.75],
92            [0.0, 1.00],
93            [0.5, 1.00],
94        ],
95    )
96    // Set mesh vertex normals
97    .with_inserted_attribute(Mesh::ATTRIBUTE_NORMAL, vec![[0.0, 0.0, 1.0]; 10])
98    // Set mesh vertex joint indices for mesh skinning.
99    // Each vertex gets 4 indices used to address the `JointTransforms` array in the vertex shader
100    //  as well as `SkinnedMeshJoint` array in the `SkinnedMesh` component.
101    // This means that a maximum of 4 joints can affect a single vertex.
102    .with_inserted_attribute(
103        Mesh::ATTRIBUTE_JOINT_INDEX,
104        // Need to be explicit here as [u16; 4] could be either Uint16x4 or Unorm16x4.
105        VertexAttributeValues::Uint16x4(vec![
106            [0, 0, 0, 0],
107            [0, 0, 0, 0],
108            [0, 1, 0, 0],
109            [0, 1, 0, 0],
110            [0, 1, 0, 0],
111            [0, 1, 0, 0],
112            [0, 1, 0, 0],
113            [0, 1, 0, 0],
114            [0, 1, 0, 0],
115            [0, 1, 0, 0],
116        ]),
117    )
118    // Set mesh vertex joint weights for mesh skinning.
119    // Each vertex gets 4 joint weights corresponding to the 4 joint indices assigned to it.
120    // The sum of these weights should equal to 1.
121    .with_inserted_attribute(
122        Mesh::ATTRIBUTE_JOINT_WEIGHT,
123        vec![
124            [1.00, 0.00, 0.0, 0.0],
125            [1.00, 0.00, 0.0, 0.0],
126            [0.75, 0.25, 0.0, 0.0],
127            [0.75, 0.25, 0.0, 0.0],
128            [0.50, 0.50, 0.0, 0.0],
129            [0.50, 0.50, 0.0, 0.0],
130            [0.25, 0.75, 0.0, 0.0],
131            [0.25, 0.75, 0.0, 0.0],
132            [0.00, 1.00, 0.0, 0.0],
133            [0.00, 1.00, 0.0, 0.0],
134        ],
135    )
136    // Tell bevy to construct triangles from a list of vertex indices,
137    // where each 3 vertex indices form a triangle.
138    .with_inserted_indices(Indices::U16(vec![
139        0, 1, 3, 0, 3, 2, 2, 3, 5, 2, 5, 4, 4, 5, 7, 4, 7, 6, 6, 7, 9, 6, 9, 8,
140    ]));
141
142    let mesh = meshes.add(mesh);
143
144    // We're seeding the PRNG here to make this example deterministic for testing purposes.
145    // This isn't strictly required in practical use unless you need your app to be deterministic.
146    let mut rng = ChaCha8Rng::seed_from_u64(42);
147
148    for i in -5..5 {
149        // Create joint entities
150        let joint_0 = commands
151            .spawn(Transform::from_xyz(
152                i as f32 * 1.5,
153                0.0,
154                // Move quads back a small amount to avoid Z-fighting and not
155                // obscure the transform gizmos.
156                -(i as f32 * 0.01).abs(),
157            ))
158            .id();
159        let joint_1 = commands.spawn((AnimatedJoint(i), Transform::IDENTITY)).id();
160
161        // Set joint_1 as a child of joint_0.
162        commands.entity(joint_0).add_children(&[joint_1]);
163
164        // Each joint in this vector corresponds to each inverse bindpose matrix in `SkinnedMeshInverseBindposes`.
165        let joint_entities = vec![joint_0, joint_1];
166
167        // Create skinned mesh renderer. Note that its transform doesn't affect the position of the mesh.
168        commands.spawn((
169            Mesh3d(mesh.clone()),
170            MeshMaterial3d(materials.add(StandardMaterial {
171                base_color: Color::srgb(
172                    rng.gen_range(0.0..1.0),
173                    rng.gen_range(0.0..1.0),
174                    rng.gen_range(0.0..1.0),
175                ),
176                base_color_texture: Some(asset_server.load("textures/uv_checker_bw.png")),
177                ..default()
178            })),
179            SkinnedMesh {
180                inverse_bindposes: inverse_bindposes.clone(),
181                joints: joint_entities,
182            },
183        ));
184    }
185}
examples/ui/text_debug.rs (line 245)
33fn infotext_system(mut commands: Commands, asset_server: Res<AssetServer>) {
34    let font = asset_server.load("fonts/FiraSans-Bold.ttf");
35    let background_color = MAROON.into();
36    commands.spawn(Camera2d);
37
38    let root_uinode = commands
39        .spawn(Node {
40            width: Val::Percent(100.),
41            height: Val::Percent(100.),
42            justify_content: JustifyContent::SpaceBetween,
43            ..default()
44        })
45        .id();
46
47    let left_column = commands
48        .spawn(Node {
49            flex_direction: FlexDirection::Column,
50            justify_content: JustifyContent::SpaceBetween,
51            align_items: AlignItems::Start,
52            flex_grow: 1.,
53            margin: UiRect::axes(Val::Px(15.), Val::Px(5.)),
54            ..default()
55        }).with_children(|builder| {
56        builder.spawn((
57            Text::new("This is\ntext with\nline breaks\nin the top left."),
58            TextFont {
59                font: font.clone(),
60                font_size: 25.0,
61                ..default()
62            },
63            BackgroundColor(background_color)
64        ));
65        builder.spawn((
66            Text::new(
67                "This text is right-justified. The `JustifyText` component controls the horizontal alignment of the lines of multi-line text relative to each other, and does not affect the text node's position in the UI layout.",
68            ),
69            TextFont {
70                font: font.clone(),
71                font_size: 25.0,
72                ..default()
73            },
74            TextColor(YELLOW.into()),
75            TextLayout::new_with_justify(JustifyText::Right),
76            Node {
77                max_width: Val::Px(300.),
78                ..default()
79            },
80            BackgroundColor(background_color)
81        ));
82        builder.spawn((
83            Text::new(
84                "This\ntext has\nline breaks and also a set width in the bottom left."),
85            TextFont {
86                font: font.clone(),
87                font_size: 25.0,
88                ..default()
89            },
90            Node {
91                max_width: Val::Px(300.),
92                ..default()
93            },
94            BackgroundColor(background_color)
95        )
96        );
97    }).id();
98
99    let right_column = commands
100        .spawn(Node {
101            flex_direction: FlexDirection::Column,
102            justify_content: JustifyContent::SpaceBetween,
103            align_items: AlignItems::End,
104            flex_grow: 1.,
105            margin: UiRect::axes(Val::Px(15.), Val::Px(5.)),
106            ..default()
107        })
108        .with_children(|builder| {
109            builder.spawn((
110                Text::new("This text is very long, has a limited width, is center-justified, is positioned in the top right and is also colored pink."),
111                TextFont {
112                    font: font.clone(),
113                    font_size: 33.0,
114                    ..default()
115                },
116                TextColor(Color::srgb(0.8, 0.2, 0.7)),
117                TextLayout::new_with_justify(JustifyText::Center),
118                Node {
119                    max_width: Val::Px(400.),
120                    ..default()
121                },
122                BackgroundColor(background_color),
123            ));
124
125            builder.spawn((
126                Text::new("This text is left-justified and is vertically positioned to distribute the empty space equally above and below it."),
127                TextFont {
128                    font: font.clone(),
129                    font_size: 29.0,
130                    ..default()
131                },
132                TextColor(YELLOW.into()),
133                TextLayout::new_with_justify(JustifyText::Left),
134                Node {
135                    max_width: Val::Px(300.),
136                    ..default()
137                },
138                BackgroundColor(background_color),
139            ));
140
141            builder.spawn((
142                Text::new("This text is fully justified and is positioned in the same way."),
143                TextFont {
144                    font: font.clone(),
145                    font_size: 29.0,
146                    ..default()
147                },
148                TextLayout::new_with_justify(JustifyText::Justified),
149                TextColor(GREEN_YELLOW.into()),
150                Node {
151                    max_width: Val::Px(300.),
152                    ..default()
153                },
154                BackgroundColor(background_color),
155            ));
156
157            builder
158                .spawn((
159                    Text::default(),
160                    TextFont {
161                        font: font.clone(),
162                        font_size: 21.0,
163                        ..default()
164                    },
165                    TextChanges,
166                    BackgroundColor(background_color),
167                ))
168                .with_children(|p| {
169                    p.spawn((
170                        TextSpan::new("\nThis text changes in the bottom right"),
171                        TextFont {
172                            font: font.clone(),
173                            font_size: 21.0,
174                            ..default()
175                        },
176                    ));
177                    p.spawn((
178                        TextSpan::new(" this text has zero font size"),
179                        TextFont {
180                            font: font.clone(),
181                            font_size: 0.0,
182                            ..default()
183                        },
184                        TextColor(BLUE.into()),
185                    ));
186                    p.spawn((
187                        TextSpan::new("\nThis text changes in the bottom right - "),
188                        TextFont {
189                            font: font.clone(),
190                            font_size: 21.0,
191                            ..default()
192                        },
193                        TextColor(RED.into()),
194                    ));
195                    p.spawn((
196                        TextSpan::default(),
197                        TextFont {
198                            font: font.clone(),
199                            font_size: 21.0,
200                            ..default()
201                        },
202                        TextColor(ORANGE_RED.into()),
203                    ));
204                    p.spawn((
205                        TextSpan::new(" fps, "),
206                        TextFont {
207                            font: font.clone(),
208                            font_size: 10.0,
209                            ..default()
210                        },
211                        TextColor(YELLOW.into()),
212                    ));
213                    p.spawn((
214                        TextSpan::default(),
215                        TextFont {
216                            font: font.clone(),
217                            font_size: 21.0,
218                            ..default()
219                        },
220                        TextColor(LIME.into()),
221                    ));
222                    p.spawn((
223                        TextSpan::new(" ms/frame"),
224                        TextFont {
225                            font: font.clone(),
226                            font_size: 42.0,
227                            ..default()
228                        },
229                        TextColor(BLUE.into()),
230                    ));
231                    p.spawn((
232                        TextSpan::new(" this text has negative font size"),
233                        TextFont {
234                            font: font.clone(),
235                            font_size: -42.0,
236                            ..default()
237                        },
238                        TextColor(BLUE.into()),
239                    ));
240                });
241        })
242        .id();
243    commands
244        .entity(root_uinode)
245        .add_children(&[left_column, right_column]);
246}
examples/ui/borders.rs (line 170)
12fn setup(mut commands: Commands) {
13    commands.spawn(Camera2d);
14    let root = commands
15        .spawn((
16            Node {
17                margin: UiRect::all(Val::Px(25.0)),
18                align_self: AlignSelf::Stretch,
19                justify_self: JustifySelf::Stretch,
20                flex_wrap: FlexWrap::Wrap,
21                justify_content: JustifyContent::FlexStart,
22                align_items: AlignItems::FlexStart,
23                align_content: AlignContent::FlexStart,
24                ..default()
25            },
26            BackgroundColor(Color::srgb(0.25, 0.25, 0.25)),
27        ))
28        .id();
29
30    let root_rounded = commands
31        .spawn((
32            Node {
33                margin: UiRect::all(Val::Px(25.0)),
34                align_self: AlignSelf::Stretch,
35                justify_self: JustifySelf::Stretch,
36                flex_wrap: FlexWrap::Wrap,
37                justify_content: JustifyContent::FlexStart,
38                align_items: AlignItems::FlexStart,
39                align_content: AlignContent::FlexStart,
40                ..default()
41            },
42            BackgroundColor(Color::srgb(0.25, 0.25, 0.25)),
43        ))
44        .id();
45
46    // labels for the different border edges
47    let border_labels = [
48        "None",
49        "All",
50        "Left",
51        "Right",
52        "Top",
53        "Bottom",
54        "Horizontal",
55        "Vertical",
56        "Top Left",
57        "Bottom Left",
58        "Top Right",
59        "Bottom Right",
60        "Top Bottom Right",
61        "Top Bottom Left",
62        "Top Left Right",
63        "Bottom Left Right",
64    ];
65
66    // all the different combinations of border edges
67    // these correspond to the labels above
68    let borders = [
69        UiRect::default(),
70        UiRect::all(Val::Px(10.)),
71        UiRect::left(Val::Px(10.)),
72        UiRect::right(Val::Px(10.)),
73        UiRect::top(Val::Px(10.)),
74        UiRect::bottom(Val::Px(10.)),
75        UiRect::horizontal(Val::Px(10.)),
76        UiRect::vertical(Val::Px(10.)),
77        UiRect {
78            left: Val::Px(20.),
79            top: Val::Px(10.),
80            ..Default::default()
81        },
82        UiRect {
83            left: Val::Px(10.),
84            bottom: Val::Px(20.),
85            ..Default::default()
86        },
87        UiRect {
88            right: Val::Px(20.),
89            top: Val::Px(10.),
90            ..Default::default()
91        },
92        UiRect {
93            right: Val::Px(10.),
94            bottom: Val::Px(10.),
95            ..Default::default()
96        },
97        UiRect {
98            right: Val::Px(10.),
99            top: Val::Px(20.),
100            bottom: Val::Px(10.),
101            ..Default::default()
102        },
103        UiRect {
104            left: Val::Px(10.),
105            top: Val::Px(10.),
106            bottom: Val::Px(10.),
107            ..Default::default()
108        },
109        UiRect {
110            left: Val::Px(20.),
111            right: Val::Px(10.),
112            top: Val::Px(10.),
113            ..Default::default()
114        },
115        UiRect {
116            left: Val::Px(10.),
117            right: Val::Px(10.),
118            bottom: Val::Px(20.),
119            ..Default::default()
120        },
121    ];
122
123    for (label, border) in border_labels.into_iter().zip(borders) {
124        let inner_spot = commands
125            .spawn((
126                Node {
127                    width: Val::Px(10.),
128                    height: Val::Px(10.),
129                    ..default()
130                },
131                BackgroundColor(YELLOW.into()),
132            ))
133            .id();
134        let border_node = commands
135            .spawn((
136                Node {
137                    width: Val::Px(50.),
138                    height: Val::Px(50.),
139                    border,
140                    margin: UiRect::all(Val::Px(20.)),
141                    align_items: AlignItems::Center,
142                    justify_content: JustifyContent::Center,
143                    ..default()
144                },
145                BackgroundColor(MAROON.into()),
146                BorderColor(RED.into()),
147                Outline {
148                    width: Val::Px(6.),
149                    offset: Val::Px(6.),
150                    color: Color::WHITE,
151                },
152            ))
153            .add_child(inner_spot)
154            .id();
155        let label_node = commands
156            .spawn((
157                Text::new(label),
158                TextFont {
159                    font_size: 9.0,
160                    ..Default::default()
161                },
162            ))
163            .id();
164        let container = commands
165            .spawn(Node {
166                flex_direction: FlexDirection::Column,
167                align_items: AlignItems::Center,
168                ..default()
169            })
170            .add_children(&[border_node, label_node])
171            .id();
172        commands.entity(root).add_child(container);
173    }
174
175    for (label, border) in border_labels.into_iter().zip(borders) {
176        let inner_spot = commands
177            .spawn((
178                Node {
179                    width: Val::Px(10.),
180                    height: Val::Px(10.),
181                    ..default()
182                },
183                BorderRadius::MAX,
184                BackgroundColor(YELLOW.into()),
185            ))
186            .id();
187        let non_zero = |x, y| x != Val::Px(0.) && y != Val::Px(0.);
188        let border_size = |x, y| if non_zero(x, y) { f32::MAX } else { 0. };
189        let border_radius = BorderRadius::px(
190            border_size(border.left, border.top),
191            border_size(border.right, border.top),
192            border_size(border.right, border.bottom),
193            border_size(border.left, border.bottom),
194        );
195        let border_node = commands
196            .spawn((
197                Node {
198                    width: Val::Px(50.),
199                    height: Val::Px(50.),
200                    border,
201                    margin: UiRect::all(Val::Px(20.)),
202                    align_items: AlignItems::Center,
203                    justify_content: JustifyContent::Center,
204                    ..default()
205                },
206                BackgroundColor(MAROON.into()),
207                BorderColor(RED.into()),
208                border_radius,
209                Outline {
210                    width: Val::Px(6.),
211                    offset: Val::Px(6.),
212                    color: Color::WHITE,
213                },
214            ))
215            .add_child(inner_spot)
216            .id();
217        let label_node = commands
218            .spawn((
219                Text::new(label),
220                TextFont {
221                    font_size: 9.0,
222                    ..Default::default()
223                },
224            ))
225            .id();
226        let container = commands
227            .spawn(Node {
228                flex_direction: FlexDirection::Column,
229                align_items: AlignItems::Center,
230                ..default()
231            })
232            .add_children(&[border_node, label_node])
233            .id();
234        commands.entity(root_rounded).add_child(container);
235    }
236
237    let border_label = commands
238        .spawn((
239            Node {
240                margin: UiRect {
241                    left: Val::Px(25.0),
242                    right: Val::Px(25.0),
243                    top: Val::Px(25.0),
244                    bottom: Val::Px(0.0),
245                },
246                ..default()
247            },
248            BackgroundColor(Color::srgb(0.25, 0.25, 0.25)),
249        ))
250        .with_children(|builder| {
251            builder.spawn((
252                Text::new("Borders"),
253                TextFont {
254                    font_size: 20.0,
255                    ..Default::default()
256                },
257            ));
258        })
259        .id();
260
261    let border_rounded_label = commands
262        .spawn((
263            Node {
264                margin: UiRect {
265                    left: Val::Px(25.0),
266                    right: Val::Px(25.0),
267                    top: Val::Px(25.0),
268                    bottom: Val::Px(0.0),
269                },
270                ..default()
271            },
272            BackgroundColor(Color::srgb(0.25, 0.25, 0.25)),
273        ))
274        .with_children(|builder| {
275            builder.spawn((
276                Text::new("Borders Rounded"),
277                TextFont {
278                    font_size: 20.0,
279                    ..Default::default()
280                },
281            ));
282        })
283        .id();
284
285    commands
286        .spawn((
287            Node {
288                margin: UiRect::all(Val::Px(25.0)),
289                flex_direction: FlexDirection::Column,
290                align_self: AlignSelf::Stretch,
291                justify_self: JustifySelf::Stretch,
292                flex_wrap: FlexWrap::Wrap,
293                justify_content: JustifyContent::FlexStart,
294                align_items: AlignItems::FlexStart,
295                align_content: AlignContent::FlexStart,
296                ..default()
297            },
298            BackgroundColor(Color::srgb(0.25, 0.25, 0.25)),
299        ))
300        .add_child(border_label)
301        .add_child(root)
302        .add_child(border_rounded_label)
303        .add_child(root_rounded);
304}
Source

pub fn insert_children( &mut self, index: usize, children: &[Entity], ) -> &mut EntityCommands<'a>

Insert children at specific index. See also insert_related.

Source

pub fn add_child(&mut self, child: Entity) -> &mut EntityCommands<'a>

Adds the given child to this entity

Examples found in repository?
examples/ecs/hierarchy.rs (line 58)
19fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
20    commands.spawn(Camera2d);
21    let texture = asset_server.load("branding/icon.png");
22
23    // Spawn a root entity with no parent
24    let parent = commands
25        .spawn((
26            Sprite::from_image(texture.clone()),
27            Transform::from_scale(Vec3::splat(0.75)),
28        ))
29        // With that entity as a parent, run a lambda that spawns its children
30        .with_children(|parent| {
31            // parent is a ChildSpawnerCommands, which has a similar API to Commands
32            parent.spawn((
33                Transform::from_xyz(250.0, 0.0, 0.0).with_scale(Vec3::splat(0.75)),
34                Sprite {
35                    image: texture.clone(),
36                    color: BLUE.into(),
37                    ..default()
38                },
39            ));
40        })
41        // Store parent entity for next sections
42        .id();
43
44    // Another way is to use the add_child function to add children after the parent
45    // entity has already been spawned.
46    let child = commands
47        .spawn((
48            Sprite {
49                image: texture,
50                color: LIME.into(),
51                ..default()
52            },
53            Transform::from_xyz(0.0, 250.0, 0.0).with_scale(Vec3::splat(0.75)),
54        ))
55        .id();
56
57    // Add child to the parent.
58    commands.entity(parent).add_child(child);
59}
More examples
Hide additional examples
examples/3d/occlusion_culling.rs (line 331)
284fn spawn_small_cubes(
285    commands: &mut Commands,
286    meshes: &mut Assets<Mesh>,
287    materials: &mut Assets<StandardMaterial>,
288) {
289    // Add the cube mesh.
290    let small_cube = meshes.add(Cuboid::new(
291        SMALL_CUBE_SIZE,
292        SMALL_CUBE_SIZE,
293        SMALL_CUBE_SIZE,
294    ));
295
296    // Add the cube material.
297    let small_cube_material = materials.add(StandardMaterial {
298        base_color: SILVER.into(),
299        ..default()
300    });
301
302    // Create the entity that the small cubes will be parented to. This is the
303    // entity that we rotate.
304    let sphere_parent = commands
305        .spawn(Transform::from_translation(Vec3::ZERO))
306        .insert(Visibility::default())
307        .insert(SphereParent)
308        .id();
309
310    // Now we have to figure out where to place the cubes. To do that, we create
311    // a sphere mesh, but we don't add it to the scene. Instead, we inspect the
312    // sphere mesh to find the positions of its vertices, and spawn a small cube
313    // at each one. That way, we end up with a bunch of cubes arranged in a
314    // spherical shape.
315
316    // Create the sphere mesh, and extract the positions of its vertices.
317    let sphere = Sphere::new(OUTER_RADIUS)
318        .mesh()
319        .ico(OUTER_SUBDIVISION_COUNT)
320        .unwrap();
321    let sphere_positions = sphere.attribute(Mesh::ATTRIBUTE_POSITION).unwrap();
322
323    // At each vertex, create a small cube.
324    for sphere_position in sphere_positions.as_float3().unwrap() {
325        let sphere_position = Vec3::from_slice(sphere_position);
326        let small_cube = commands
327            .spawn(Mesh3d(small_cube.clone()))
328            .insert(MeshMaterial3d(small_cube_material.clone()))
329            .insert(Transform::from_translation(sphere_position))
330            .id();
331        commands.entity(sphere_parent).add_child(small_cube);
332    }
333}
examples/animation/animation_graph.rs (line 329)
265fn setup_node_rects(commands: &mut Commands) {
266    for (node_rect, node_type) in NODE_RECTS.iter().zip(NODE_TYPES.iter()) {
267        let node_string = match *node_type {
268            NodeType::Clip(ref clip) => clip.text,
269            NodeType::Blend(text) => text,
270        };
271
272        let text = commands
273            .spawn((
274                Text::new(node_string),
275                TextFont {
276                    font_size: 16.0,
277                    ..default()
278                },
279                TextColor(ANTIQUE_WHITE.into()),
280                TextLayout::new_with_justify(JustifyText::Center),
281            ))
282            .id();
283
284        let container = {
285            let mut container = commands.spawn((
286                Node {
287                    position_type: PositionType::Absolute,
288                    bottom: Val::Px(node_rect.bottom),
289                    left: Val::Px(node_rect.left),
290                    height: Val::Px(node_rect.height),
291                    width: Val::Px(node_rect.width),
292                    align_items: AlignItems::Center,
293                    justify_items: JustifyItems::Center,
294                    align_content: AlignContent::Center,
295                    justify_content: JustifyContent::Center,
296                    ..default()
297                },
298                BorderColor(WHITE.into()),
299                Outline::new(Val::Px(1.), Val::ZERO, Color::WHITE),
300            ));
301
302            if let NodeType::Clip(clip) = node_type {
303                container.insert((
304                    Interaction::None,
305                    RelativeCursorPosition::default(),
306                    (*clip).clone(),
307                ));
308            }
309
310            container.id()
311        };
312
313        // Create the background color.
314        if let NodeType::Clip(_) = node_type {
315            let background = commands
316                .spawn((
317                    Node {
318                        position_type: PositionType::Absolute,
319                        top: Val::Px(0.),
320                        left: Val::Px(0.),
321                        height: Val::Px(node_rect.height),
322                        width: Val::Px(node_rect.width),
323                        ..default()
324                    },
325                    BackgroundColor(DARK_GREEN.into()),
326                ))
327                .id();
328
329            commands.entity(container).add_child(background);
330        }
331
332        commands.entity(container).add_child(text);
333    }
334}
examples/3d/irradiance_volumes.rs (line 590)
526fn create_cubes(
527    image_assets: Res<Assets<Image>>,
528    mut commands: Commands,
529    irradiance_volumes: Query<(&IrradianceVolume, &GlobalTransform)>,
530    voxel_cube_parents: Query<Entity, With<VoxelCubeParent>>,
531    voxel_cubes: Query<Entity, With<VoxelCube>>,
532    example_assets: Res<ExampleAssets>,
533    mut voxel_visualization_material_assets: ResMut<Assets<VoxelVisualizationMaterial>>,
534) {
535    // If voxel cubes have already been spawned, don't do anything.
536    if !voxel_cubes.is_empty() {
537        return;
538    }
539
540    let Some(voxel_cube_parent) = voxel_cube_parents.iter().next() else {
541        return;
542    };
543
544    for (irradiance_volume, global_transform) in irradiance_volumes.iter() {
545        let Some(image) = image_assets.get(&irradiance_volume.voxels) else {
546            continue;
547        };
548
549        let resolution = image.texture_descriptor.size;
550
551        let voxel_cube_material = voxel_visualization_material_assets.add(ExtendedMaterial {
552            base: StandardMaterial::from(Color::from(RED)),
553            extension: VoxelVisualizationExtension {
554                irradiance_volume_info: VoxelVisualizationIrradianceVolumeInfo {
555                    world_from_voxel: VOXEL_FROM_WORLD.inverse(),
556                    voxel_from_world: VOXEL_FROM_WORLD,
557                    resolution: uvec3(
558                        resolution.width,
559                        resolution.height,
560                        resolution.depth_or_array_layers,
561                    ),
562                    intensity: IRRADIANCE_VOLUME_INTENSITY,
563                },
564            },
565        });
566
567        let scale = vec3(
568            1.0 / resolution.width as f32,
569            1.0 / resolution.height as f32,
570            1.0 / resolution.depth_or_array_layers as f32,
571        );
572
573        // Spawn a cube for each voxel.
574        for z in 0..resolution.depth_or_array_layers {
575            for y in 0..resolution.height {
576                for x in 0..resolution.width {
577                    let uvw = (uvec3(x, y, z).as_vec3() + 0.5) * scale - 0.5;
578                    let pos = global_transform.transform_point(uvw);
579                    let voxel_cube = commands
580                        .spawn((
581                            Mesh3d(example_assets.voxel_cube.clone()),
582                            MeshMaterial3d(voxel_cube_material.clone()),
583                            Transform::from_scale(Vec3::splat(VOXEL_CUBE_SCALE))
584                                .with_translation(pos),
585                        ))
586                        .insert(VoxelCube)
587                        .insert(NotShadowCaster)
588                        .id();
589
590                    commands.entity(voxel_cube_parent).add_child(voxel_cube);
591                }
592            }
593        }
594    }
595}
examples/stress_tests/transform_hierarchy.rs (line 430)
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}
examples/ui/text_wrap_debug.rs (line 124)
45fn spawn(mut commands: Commands, asset_server: Res<AssetServer>) {
46    commands.spawn(Camera2d);
47
48    let text_font = TextFont {
49        font: asset_server.load("fonts/FiraSans-Bold.ttf"),
50        font_size: 12.0,
51        ..default()
52    };
53
54    let root = commands
55        .spawn((
56            Node {
57                width: Val::Percent(100.),
58                height: Val::Percent(100.),
59                flex_direction: FlexDirection::Column,
60                ..default()
61            },
62            BackgroundColor(Color::BLACK),
63        ))
64        .id();
65
66    for linebreak in [
67        LineBreak::AnyCharacter,
68        LineBreak::WordBoundary,
69        LineBreak::WordOrCharacter,
70        LineBreak::NoWrap,
71    ] {
72        let row_id = commands
73            .spawn(Node {
74                flex_direction: FlexDirection::Row,
75                justify_content: JustifyContent::SpaceAround,
76                align_items: AlignItems::Center,
77                width: Val::Percent(100.),
78                height: Val::Percent(50.),
79                ..default()
80            })
81            .id();
82
83        let justifications = vec![
84            JustifyContent::Center,
85            JustifyContent::FlexStart,
86            JustifyContent::FlexEnd,
87            JustifyContent::SpaceAround,
88            JustifyContent::SpaceBetween,
89            JustifyContent::SpaceEvenly,
90        ];
91
92        for (i, justification) in justifications.into_iter().enumerate() {
93            let c = 0.3 + i as f32 * 0.1;
94            let column_id = commands
95                .spawn((
96                    Node {
97                        justify_content: justification,
98                        flex_direction: FlexDirection::Column,
99                        width: Val::Percent(16.),
100                        height: Val::Percent(95.),
101                        overflow: Overflow::clip_x(),
102                        ..default()
103                    },
104                    BackgroundColor(Color::srgb(0.5, c, 1.0 - c)),
105                ))
106                .id();
107
108            let messages = [
109                format!("JustifyContent::{justification:?}"),
110                format!("LineBreakOn::{linebreak:?}"),
111                "Line 1\nLine 2".to_string(),
112                "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas auctor, nunc ac faucibus fringilla.".to_string(),
113                "pneumonoultramicroscopicsilicovolcanoconiosis".to_string()
114            ];
115
116            for (j, message) in messages.into_iter().enumerate() {
117                commands.entity(column_id).with_child((
118                    Text(message.clone()),
119                    text_font.clone(),
120                    TextLayout::new(JustifyText::Left, linebreak),
121                    BackgroundColor(Color::srgb(0.8 - j as f32 * 0.2, 0., 0.)),
122                ));
123            }
124            commands.entity(row_id).add_child(column_id);
125        }
126        commands.entity(root).add_child(row_id);
127    }
128}
Source

pub fn remove_children( &mut self, children: &[Entity], ) -> &mut EntityCommands<'a>

Removes the relationship between this entity and the given entities.

Source

pub fn replace_children( &mut self, children: &[Entity], ) -> &mut EntityCommands<'a>

Replaces the children on this entity with a new list of children.

Source

pub fn replace_children_with_difference( &mut self, entities_to_unrelate: &[Entity], entities_to_relate: &[Entity], newly_related_entities: &[Entity], ) -> &mut EntityCommands<'a>

Replaces all the related entities with a new set of entities.

§Warning

Failing to maintain the functions invariants may lead to erratic engine behavior including random crashes. Refer to EntityWorldMut::replace_related_with_difference for a list of these invariants.

§Panics

Panics when debug assertions are enabled if an invariant is is broken and the command is executed.

Source

pub fn with_child(&mut self, bundle: impl Bundle) -> &mut EntityCommands<'a>

Spawns the passed bundle and adds it to this entity as a child.

For efficient spawning of multiple children, use with_children.

Examples found in repository?
examples/movement/physics_in_fixed_timestep.rs (lines 154-160)
146fn spawn_text(mut commands: Commands) {
147    commands
148        .spawn(Node {
149            position_type: PositionType::Absolute,
150            bottom: Val::Px(12.0),
151            left: Val::Px(12.0),
152            ..default()
153        })
154        .with_child((
155            Text::new("Move the player with WASD"),
156            TextFont {
157                font_size: 25.0,
158                ..default()
159            },
160        ));
161}
More examples
Hide additional examples
examples/window/window_resizing.rs (lines 43-50)
35fn setup_ui(mut commands: Commands) {
36    // Node that fills entire background
37    commands
38        .spawn(Node {
39            width: Val::Percent(100.),
40            ..default()
41        })
42        // Text where we display current resolution
43        .with_child((
44            Text::new("Resolution"),
45            TextFont {
46                font_size: 42.0,
47                ..default()
48            },
49            ResolutionText,
50        ));
51}
examples/camera/first_person_view_model.rs (lines 201-205)
193fn spawn_text(mut commands: Commands) {
194    commands
195        .spawn(Node {
196            position_type: PositionType::Absolute,
197            bottom: Val::Px(12.0),
198            left: Val::Px(12.0),
199            ..default()
200        })
201        .with_child(Text::new(concat!(
202            "Move the camera with your mouse.\n",
203            "Press arrow up to decrease the FOV of the world model.\n",
204            "Press arrow down to increase the FOV of the world model."
205        )));
206}
examples/games/contributors.rs (lines 159-165)
138fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
139    commands.spawn(Camera2d);
140
141    let text_style = TextFont {
142        font: asset_server.load("fonts/FiraSans-Bold.ttf"),
143        font_size: 60.0,
144        ..default()
145    };
146
147    commands
148        .spawn((
149            Text::new("Contributor showcase"),
150            text_style.clone(),
151            ContributorDisplay,
152            Node {
153                position_type: PositionType::Absolute,
154                top: Val::Px(12.),
155                left: Val::Px(12.),
156                ..default()
157            },
158        ))
159        .with_child((
160            TextSpan::default(),
161            TextFont {
162                font_size: 30.,
163                ..text_style
164            },
165        ));
166}
examples/games/loading_screen.rs (line 93)
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}
95
96// Selects the level you want to load.
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}
114
115// Marker component for easier deletion of entities.
116#[derive(Component)]
117struct LevelComponents;
118
119// Removes all currently loaded level assets from the game World.
120fn unload_current_level(
121    mut commands: Commands,
122    mut loading_state: ResMut<LoadingState>,
123    entities: Query<Entity, With<LevelComponents>>,
124) {
125    *loading_state = LoadingState::LevelLoading;
126    for entity in entities.iter() {
127        commands.entity(entity).despawn();
128    }
129}
130
131fn load_level_1(
132    mut commands: Commands,
133    mut loading_data: ResMut<LoadingData>,
134    asset_server: Res<AssetServer>,
135) {
136    // Spawn the camera.
137    commands.spawn((
138        Camera3d::default(),
139        Transform::from_xyz(155.0, 155.0, 155.0).looking_at(Vec3::new(0.0, 40.0, 0.0), Vec3::Y),
140        LevelComponents,
141    ));
142
143    // Save the asset into the `loading_assets` vector.
144    let fox = asset_server.load(GltfAssetLabel::Scene(0).from_asset("models/animated/Fox.glb"));
145    loading_data.loading_assets.push(fox.clone().into());
146    // Spawn the fox.
147    commands.spawn((
148        SceneRoot(fox.clone()),
149        Transform::from_xyz(0.0, 0.0, 0.0),
150        LevelComponents,
151    ));
152
153    // Spawn the light.
154    commands.spawn((
155        DirectionalLight {
156            shadows_enabled: true,
157            ..default()
158        },
159        Transform::from_xyz(3.0, 3.0, 2.0).looking_at(Vec3::ZERO, Vec3::Y),
160        LevelComponents,
161    ));
162}
163
164fn load_level_2(
165    mut commands: Commands,
166    mut loading_data: ResMut<LoadingData>,
167    asset_server: Res<AssetServer>,
168) {
169    // Spawn the camera.
170    commands.spawn((
171        Camera3d::default(),
172        Transform::from_xyz(1.0, 1.0, 1.0).looking_at(Vec3::new(0.0, 0.2, 0.0), Vec3::Y),
173        LevelComponents,
174    ));
175
176    // Spawn the helmet.
177    let helmet_scene = asset_server
178        .load(GltfAssetLabel::Scene(0).from_asset("models/FlightHelmet/FlightHelmet.gltf"));
179    loading_data
180        .loading_assets
181        .push(helmet_scene.clone().into());
182    commands.spawn((SceneRoot(helmet_scene.clone()), LevelComponents));
183
184    // Spawn the light.
185    commands.spawn((
186        DirectionalLight {
187            shadows_enabled: true,
188            ..default()
189        },
190        Transform::from_xyz(3.0, 3.0, 2.0).looking_at(Vec3::ZERO, Vec3::Y),
191        LevelComponents,
192    ));
193}
194
195// Monitors current loading status of assets.
196fn update_loading_data(
197    mut loading_data: ResMut<LoadingData>,
198    mut loading_state: ResMut<LoadingState>,
199    asset_server: Res<AssetServer>,
200    pipelines_ready: Res<PipelinesReady>,
201) {
202    if !loading_data.loading_assets.is_empty() || !pipelines_ready.0 {
203        // If we are still loading assets / pipelines are not fully compiled,
204        // we reset the confirmation frame count.
205        loading_data.confirmation_frames_count = 0;
206
207        loading_data.loading_assets.retain(|asset| {
208            asset_server
209                .get_recursive_dependency_load_state(asset)
210                .is_none_or(|state| !state.is_loaded())
211        });
212
213        // If there are no more assets being monitored, and pipelines
214        // are compiled, then start counting confirmation frames.
215        // Once enough confirmations have passed, everything will be
216        // considered to be fully loaded.
217    } else {
218        loading_data.confirmation_frames_count += 1;
219        if loading_data.confirmation_frames_count == loading_data.confirmation_frames_target {
220            *loading_state = LoadingState::LevelReady;
221        }
222    }
223}
224
225// Marker tag for loading screen components.
226#[derive(Component)]
227struct LoadingScreen;
228
229// Spawns the necessary components for the loading screen.
230fn load_loading_screen(mut commands: Commands) {
231    let text_style = TextFont {
232        font_size: 67.0,
233        ..default()
234    };
235
236    // Spawn the UI and Loading screen camera.
237    commands.spawn((
238        Camera2d,
239        Camera {
240            order: 1,
241            ..default()
242        },
243        LoadingScreen,
244    ));
245
246    // Spawn the UI that will make up the loading screen.
247    commands
248        .spawn((
249            Node {
250                height: Val::Percent(100.0),
251                width: Val::Percent(100.0),
252                justify_content: JustifyContent::Center,
253                align_items: AlignItems::Center,
254                ..default()
255            },
256            BackgroundColor(Color::BLACK),
257            LoadingScreen,
258        ))
259        .with_child((Text::new("Loading..."), text_style.clone()));
260}
examples/window/scale_factor_override.rs (lines 49-60)
26fn setup(mut commands: Commands) {
27    // camera
28    commands.spawn(Camera2d);
29    // root node
30    commands
31        .spawn(Node {
32            width: Val::Percent(100.0),
33            height: Val::Percent(100.0),
34            justify_content: JustifyContent::SpaceBetween,
35            ..default()
36        })
37        .with_children(|parent| {
38            // left vertical fill (border)
39            parent
40                .spawn((
41                    Node {
42                        width: Val::Px(300.0),
43                        height: Val::Percent(100.0),
44                        border: UiRect::all(Val::Px(2.0)),
45                        ..default()
46                    },
47                    BackgroundColor(Color::srgb(0.65, 0.65, 0.65)),
48                ))
49                .with_child((
50                    CustomText,
51                    Text::new("Example text"),
52                    TextFont {
53                        font_size: 25.0,
54                        ..default()
55                    },
56                    Node {
57                        align_self: AlignSelf::FlexEnd,
58                        ..default()
59                    },
60                ));
61        });
62}
Source

pub fn remove_parent(&mut self) -> &mut EntityCommands<'a>

👎Deprecated since 0.16.0: Use entity_commands.remove::<ChildOf>()

Removes the ChildOf component, if it exists.

Source

pub fn set_parent(&mut self, parent: Entity) -> &mut EntityCommands<'a>

👎Deprecated since 0.16.0: Use entity_commands.insert(ChildOf(entity))

Inserts the ChildOf component with the given parent entity, if it exists.

Source§

impl<'a> EntityCommands<'a>

Spawns a entity related to this entity (with the R relationship) by taking a bundle

Examples found in repository?
examples/ecs/relationships.rs (line 60)
47    fn spawning_entities_with_relationships(mut commands: Commands) {
48        // Calling .id() after spawning an entity will return the `Entity` identifier of the spawned entity,
49        // even though the entity itself is not yet instantiated in the world.
50        // This works because Commands will reserve the entity ID before actually spawning the entity,
51        // through the use of atomic counters.
52        let alice = commands.spawn(Name::new("Alice")).id();
53        // Relations are just components, so we can add them into the bundle that we're spawning.
54        let bob = commands.spawn((Name::new("Bob"), Targeting(alice))).id();
55
56        // The `with_related` and `with_relationships` helper methods on `EntityCommands` can be used to add relations in a more ergonomic way.
57        let charlie = commands
58            .spawn((Name::new("Charlie"), Targeting(bob)))
59            // The `with_related` method will spawn a bundle with `Targeting` relationship
60            .with_related::<Targeting>(Name::new("James"))
61            // The `with_relationships` method will automatically add the `Targeting` component to any entities spawned within the closure,
62            // targeting the entity that we're calling `with_related` on.
63            .with_related_entities::<Targeting>(|related_spawner_commands| {
64                // We could spawn multiple entities here, and they would all target `charlie`.
65                related_spawner_commands.spawn(Name::new("Devon"));
66            })
67            .id();
68
69        // Simply inserting the `Targeting` component will automatically create and update the `TargetedBy` component on the target entity.
70        // We can do this at any point; not just when the entity is spawned.
71        commands.entity(alice).insert(Targeting(charlie));
72    }

Spawns entities related to this entity (with the R relationship) by taking a function that operates on a RelatedSpawner.

Examples found in repository?
examples/ecs/relationships.rs (lines 63-66)
47    fn spawning_entities_with_relationships(mut commands: Commands) {
48        // Calling .id() after spawning an entity will return the `Entity` identifier of the spawned entity,
49        // even though the entity itself is not yet instantiated in the world.
50        // This works because Commands will reserve the entity ID before actually spawning the entity,
51        // through the use of atomic counters.
52        let alice = commands.spawn(Name::new("Alice")).id();
53        // Relations are just components, so we can add them into the bundle that we're spawning.
54        let bob = commands.spawn((Name::new("Bob"), Targeting(alice))).id();
55
56        // The `with_related` and `with_relationships` helper methods on `EntityCommands` can be used to add relations in a more ergonomic way.
57        let charlie = commands
58            .spawn((Name::new("Charlie"), Targeting(bob)))
59            // The `with_related` method will spawn a bundle with `Targeting` relationship
60            .with_related::<Targeting>(Name::new("James"))
61            // The `with_relationships` method will automatically add the `Targeting` component to any entities spawned within the closure,
62            // targeting the entity that we're calling `with_related` on.
63            .with_related_entities::<Targeting>(|related_spawner_commands| {
64                // We could spawn multiple entities here, and they would all target `charlie`.
65                related_spawner_commands.spawn(Name::new("Devon"));
66            })
67            .id();
68
69        // Simply inserting the `Targeting` component will automatically create and update the `TargetedBy` component on the target entity.
70        // We can do this at any point; not just when the entity is spawned.
71        commands.entity(alice).insert(Targeting(charlie));
72    }

Relates the given entities to this entity with the relation R.

See add_one_related if you want relate only one entity.

Relates the given entities to this entity with the relation R, starting at this particular index.

If the related has duplicates, a related entity will take the index of its last occurrence in related. If the indices go out of bounds, they will be clamped into bounds. This will not re-order existing related entities unless they are in related.

Relates the given entity to this with the relation R.

See add_related if you want to relate more than one entity.

Removes the relation R between this entity and the given entities.

Replaces all the related entities with the given set of new related entities.

Replaces all the related entities with a new set of entities.

§Warning

Failing to maintain the functions invariants may lead to erratic engine behavior including random crashes. Refer to EntityWorldMut::replace_related_with_difference for a list of these invariants.

§Panics

Panics when debug assertions are enable, an invariant is are broken and the command is executed.

Despawns entities that relate to this one via the given RelationshipTarget. This entity will not be despawned.

Source

pub fn insert_recursive<S>( &mut self, bundle: impl Bundle + Clone, ) -> &mut EntityCommands<'a>

Inserts a component or bundle of components into the entity and all related entities, traversing the relationship tracked in S in a breadth-first manner.

§Warning

This method should only be called on relationships that form a tree-like structure. Any cycles will cause this method to loop infinitely.

Source

pub fn remove_recursive<S, B>(&mut self) -> &mut EntityCommands<'a>

Removes a component or bundle of components of type B from the entity and all related entities, traversing the relationship tracked in S in a breadth-first manner.

§Warning

This method should only be called on relationships that form a tree-like structure. Any cycles will cause this method to loop infinitely.

Source§

impl<'a> EntityCommands<'a>

Source

pub fn id(&self) -> Entity

Returns the Entity id of the entity.

§Example
fn my_system(mut commands: Commands) {
    let entity_id = commands.spawn_empty().id();
}
Examples found in repository?
examples/state/custom_transitions.rs (line 277)
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}
More examples
Hide additional examples
examples/state/states.rs (line 85)
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}
examples/state/sub_states.rs (line 190)
157    pub fn setup_menu(mut commands: Commands) {
158        let button_entity = commands
159            .spawn((
160                Node {
161                    // center button
162                    width: Val::Percent(100.),
163                    height: Val::Percent(100.),
164                    justify_content: JustifyContent::Center,
165                    align_items: AlignItems::Center,
166                    ..default()
167                },
168                children![(
169                    Button,
170                    Node {
171                        width: Val::Px(150.),
172                        height: Val::Px(65.),
173                        // horizontally center child text
174                        justify_content: JustifyContent::Center,
175                        // vertically center child text
176                        align_items: AlignItems::Center,
177                        ..default()
178                    },
179                    BackgroundColor(NORMAL_BUTTON),
180                    children![(
181                        Text::new("Play"),
182                        TextFont {
183                            font_size: 33.0,
184                            ..default()
185                        },
186                        TextColor(Color::srgb(0.9, 0.9, 0.9)),
187                    )]
188                )],
189            ))
190            .id();
191        commands.insert_resource(MenuData { button_entity });
192    }
examples/ecs/hierarchy.rs (line 42)
19fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
20    commands.spawn(Camera2d);
21    let texture = asset_server.load("branding/icon.png");
22
23    // Spawn a root entity with no parent
24    let parent = commands
25        .spawn((
26            Sprite::from_image(texture.clone()),
27            Transform::from_scale(Vec3::splat(0.75)),
28        ))
29        // With that entity as a parent, run a lambda that spawns its children
30        .with_children(|parent| {
31            // parent is a ChildSpawnerCommands, which has a similar API to Commands
32            parent.spawn((
33                Transform::from_xyz(250.0, 0.0, 0.0).with_scale(Vec3::splat(0.75)),
34                Sprite {
35                    image: texture.clone(),
36                    color: BLUE.into(),
37                    ..default()
38                },
39            ));
40        })
41        // Store parent entity for next sections
42        .id();
43
44    // Another way is to use the add_child function to add children after the parent
45    // entity has already been spawned.
46    let child = commands
47        .spawn((
48            Sprite {
49                image: texture,
50                color: LIME.into(),
51                ..default()
52            },
53            Transform::from_xyz(0.0, 250.0, 0.0).with_scale(Vec3::splat(0.75)),
54        ))
55        .id();
56
57    // Add child to the parent.
58    commands.entity(parent).add_child(child);
59}
examples/games/contributors.rs (line 130)
83fn setup_contributor_selection(
84    mut commands: Commands,
85    asset_server: Res<AssetServer>,
86    mut rng: ResMut<SharedRng>,
87) {
88    let contribs = contributors_or_fallback();
89
90    let texture_handle = asset_server.load("branding/icon.png");
91
92    let mut contributor_selection = ContributorSelection {
93        order: Vec::with_capacity(contribs.len()),
94        idx: 0,
95    };
96
97    for (name, num_commits) in contribs {
98        let transform = Transform::from_xyz(
99            rng.gen_range(-400.0..400.0),
100            rng.gen_range(0.0..400.0),
101            rng.r#gen(),
102        );
103        let dir = rng.gen_range(-1.0..1.0);
104        let velocity = Vec3::new(dir * 500.0, 0.0, 0.0);
105        let hue = name_to_hue(&name);
106
107        // Some sprites should be flipped for variety
108        let flipped = rng.r#gen();
109
110        let entity = commands
111            .spawn((
112                Contributor {
113                    name,
114                    num_commits,
115                    hue,
116                },
117                Velocity {
118                    translation: velocity,
119                    rotation: -dir * 5.0,
120                },
121                Sprite {
122                    image: texture_handle.clone(),
123                    custom_size: Some(Vec2::splat(SPRITE_SIZE)),
124                    color: DESELECTED.with_hue(hue).into(),
125                    flip_x: flipped,
126                    ..default()
127                },
128                transform,
129            ))
130            .id();
131
132        contributor_selection.order.push(entity);
133    }
134
135    commands.insert_resource(contributor_selection);
136}
examples/ecs/observers.rs (line 107)
72fn setup(mut commands: Commands) {
73    commands.spawn(Camera2d);
74    commands.spawn((
75        Text::new(
76            "Click on a \"Mine\" to trigger it.\n\
77            When it explodes it will trigger all overlapping mines.",
78        ),
79        Node {
80            position_type: PositionType::Absolute,
81            top: Val::Px(12.),
82            left: Val::Px(12.),
83            ..default()
84        },
85    ));
86
87    let mut rng = ChaCha8Rng::seed_from_u64(19878367467713);
88
89    commands
90        .spawn(Mine::random(&mut rng))
91        // Observers can watch for events targeting a specific entity.
92        // This will create a new observer that runs whenever the Explode event
93        // is triggered for this spawned entity.
94        .observe(explode_mine);
95
96    // We want to spawn a bunch of mines. We could just call the code above for each of them.
97    // That would create a new observer instance for every Mine entity. Having duplicate observers
98    // generally isn't worth worrying about as the overhead is low. But if you want to be maximally efficient,
99    // you can reuse observers across entities.
100    //
101    // First, observers are actually just entities with the Observer component! The `observe()` functions
102    // you've seen so far in this example are just shorthand for manually spawning an observer.
103    let mut observer = Observer::new(explode_mine);
104
105    // As we spawn entities, we can make this observer watch each of them:
106    for _ in 0..1000 {
107        let entity = commands.spawn(Mine::random(&mut rng)).id();
108        observer.watch_entity(entity);
109    }
110
111    // By spawning the Observer component, it becomes active!
112    commands.spawn(observer);
113}
Source

pub fn reborrow(&mut self) -> EntityCommands<'_>

Returns an EntityCommands with a smaller lifetime.

This is useful if you have &mut EntityCommands but you need EntityCommands.

Source

pub fn entry<T>(&mut self) -> EntityEntryCommands<'_, T>
where T: Component,

Get an EntityEntryCommands for the Component T, allowing you to modify it or insert it if it isn’t already present.

See also insert_if_new, which lets you insert a Bundle without overwriting it.

§Example
#[derive(Component)]
struct Level(u32);

fn level_up_system(mut commands: Commands, player: Res<PlayerEntity>) {
    commands
        .entity(player.entity)
        .entry::<Level>()
        // Modify the component if it exists.
        .and_modify(|mut lvl| lvl.0 += 1)
        // Otherwise, insert a default value.
        .or_insert(Level(0));
}
Source

pub fn insert(&mut self, bundle: impl Bundle) -> &mut EntityCommands<'a>

Adds a Bundle of components to the entity.

This will overwrite any previous value(s) of the same component type. See EntityCommands::insert_if_new to keep the old value instead.

§Example
#[derive(Component)]
struct Health(u32);
#[derive(Component)]
struct Strength(u32);
#[derive(Component)]
struct Defense(u32);

#[derive(Bundle)]
struct CombatBundle {
    health: Health,
    strength: Strength,
}

fn add_combat_stats_system(mut commands: Commands, player: Res<PlayerEntity>) {
    commands
        .entity(player.entity)
        // You can insert individual components:
        .insert(Defense(10))
        // You can also insert pre-defined bundles of components:
        .insert(CombatBundle {
            health: Health(100),
            strength: Strength(40),
        })
        // You can also insert tuples of components and bundles.
        // This is equivalent to the calls above:
        .insert((
            Defense(10),
            CombatBundle {
                health: Health(100),
                strength: Strength(40),
            },
        ));
}
Examples found in repository?
examples/3d/mixed_lighting.rs (line 159)
156fn spawn_camera(commands: &mut Commands) {
157    commands
158        .spawn(Camera3d::default())
159        .insert(Transform::from_xyz(-0.7, 0.7, 1.0).looking_at(vec3(0.0, 0.3, 0.0), Vec3::Y));
160}
161
162/// Spawns the scene.
163///
164/// The scene is loaded from a glTF file.
165fn spawn_scene(commands: &mut Commands, asset_server: &AssetServer) {
166    commands
167        .spawn(SceneRoot(
168            asset_server.load(
169                GltfAssetLabel::Scene(0)
170                    .from_asset("models/MixedLightingExample/MixedLightingExample.gltf"),
171            ),
172        ))
173        .observe(
174            |_: Trigger<SceneInstanceReady>,
175             mut lighting_mode_change_event_writer: EventWriter<LightingModeChanged>| {
176                // When the scene loads, send a `LightingModeChanged` event so
177                // that we set up the lightmaps.
178                lighting_mode_change_event_writer.write(LightingModeChanged);
179            },
180        );
181}
182
183/// Spawns the buttons that allow the user to change the lighting mode.
184fn spawn_buttons(commands: &mut Commands) {
185    commands
186        .spawn(widgets::main_ui_node())
187        .with_children(|parent| {
188            widgets::spawn_option_buttons(
189                parent,
190                "Lighting",
191                &[
192                    (LightingMode::Baked, "Baked"),
193                    (LightingMode::MixedDirect, "Mixed (Direct)"),
194                    (LightingMode::MixedIndirect, "Mixed (Indirect)"),
195                    (LightingMode::RealTime, "Real-Time"),
196                ],
197            );
198        });
199}
200
201/// Spawns the help text at the top of the window.
202fn spawn_help_text(commands: &mut Commands, app_status: &AppStatus) {
203    commands.spawn((
204        create_help_text(app_status),
205        Node {
206            position_type: PositionType::Absolute,
207            top: Val::Px(12.0),
208            left: Val::Px(12.0),
209            ..default()
210        },
211        HelpText,
212    ));
213}
214
215/// Adds lightmaps to and/or removes lightmaps from objects in the scene when
216/// the lighting mode changes.
217///
218/// This is also called right after the scene loads in order to set up the
219/// lightmaps.
220fn update_lightmaps(
221    mut commands: Commands,
222    asset_server: Res<AssetServer>,
223    mut materials: ResMut<Assets<StandardMaterial>>,
224    meshes: Query<(Entity, &Name, &MeshMaterial3d<StandardMaterial>), With<Mesh3d>>,
225    mut lighting_mode_change_event_reader: EventReader<LightingModeChanged>,
226    app_status: Res<AppStatus>,
227) {
228    // Only run if the lighting mode changed. (Note that a change event is fired
229    // when the scene first loads.)
230    if lighting_mode_change_event_reader.read().next().is_none() {
231        return;
232    }
233
234    // Select the lightmap to use, based on the lighting mode.
235    let lightmap: Option<Handle<Image>> = match app_status.lighting_mode {
236        LightingMode::Baked => {
237            Some(asset_server.load("lightmaps/MixedLightingExample-Baked.zstd.ktx2"))
238        }
239        LightingMode::MixedDirect => {
240            Some(asset_server.load("lightmaps/MixedLightingExample-MixedDirect.zstd.ktx2"))
241        }
242        LightingMode::MixedIndirect => {
243            Some(asset_server.load("lightmaps/MixedLightingExample-MixedIndirect.zstd.ktx2"))
244        }
245        LightingMode::RealTime => None,
246    };
247
248    'outer: for (entity, name, material) in &meshes {
249        // Add lightmaps to or remove lightmaps from the scenery objects in the
250        // scene (all objects but the sphere).
251        //
252        // Note that doing a linear search through the `LIGHTMAPS` array is
253        // inefficient, but we do it anyway in this example to improve clarity.
254        for (lightmap_name, uv_rect) in LIGHTMAPS {
255            if &**name != lightmap_name {
256                continue;
257            }
258
259            // Lightmap exposure defaults to zero, so we need to set it.
260            if let Some(ref mut material) = materials.get_mut(material) {
261                material.lightmap_exposure = LIGHTMAP_EXPOSURE;
262            }
263
264            // Add or remove the lightmap.
265            match lightmap {
266                Some(ref lightmap) => {
267                    commands.entity(entity).insert(Lightmap {
268                        image: (*lightmap).clone(),
269                        uv_rect,
270                        bicubic_sampling: false,
271                    });
272                }
273                None => {
274                    commands.entity(entity).remove::<Lightmap>();
275                }
276            }
277            continue 'outer;
278        }
279
280        // Add lightmaps to or remove lightmaps from the sphere.
281        if &**name == "Sphere" {
282            // Lightmap exposure defaults to zero, so we need to set it.
283            if let Some(ref mut material) = materials.get_mut(material) {
284                material.lightmap_exposure = LIGHTMAP_EXPOSURE;
285            }
286
287            // Add or remove the lightmap from the sphere. We only apply the
288            // lightmap in fully-baked mode.
289            match (&lightmap, app_status.lighting_mode) {
290                (Some(lightmap), LightingMode::Baked) => {
291                    commands.entity(entity).insert(Lightmap {
292                        image: (*lightmap).clone(),
293                        uv_rect: SPHERE_UV_RECT,
294                        bicubic_sampling: false,
295                    });
296                }
297                _ => {
298                    commands.entity(entity).remove::<Lightmap>();
299                }
300            }
301        }
302    }
303}
304
305/// Converts a uv rectangle from the OpenGL coordinate system (origin in the
306/// lower left) to the Vulkan coordinate system (origin in the upper left) that
307/// Bevy uses.
308///
309/// For this particular example, the baking tool happened to use the OpenGL
310/// coordinate system, so it was more convenient to do the conversion at compile
311/// time than to pre-calculate and hard-code the values.
312const fn uv_rect_opengl(gl_min: Vec2, size: Vec2) -> Rect {
313    let min = vec2(gl_min.x, 1.0 - gl_min.y - size.y);
314    Rect {
315        min,
316        max: vec2(min.x + size.x, min.y + size.y),
317    }
318}
319
320/// Ensures that clicking on the scene to move the sphere doesn't result in a
321/// hit on the sphere itself.
322fn make_sphere_nonpickable(
323    mut commands: Commands,
324    mut query: Query<(Entity, &Name), (With<Mesh3d>, Without<Pickable>)>,
325) {
326    for (sphere, name) in &mut query {
327        if &**name == "Sphere" {
328            commands.entity(sphere).insert(Pickable::IGNORE);
329        }
330    }
331}
332
333/// Updates the directional light settings as necessary when the lighting mode
334/// changes.
335fn update_directional_light(
336    mut lights: Query<&mut DirectionalLight>,
337    mut lighting_mode_change_event_reader: EventReader<LightingModeChanged>,
338    app_status: Res<AppStatus>,
339) {
340    // Only run if the lighting mode changed. (Note that a change event is fired
341    // when the scene first loads.)
342    if lighting_mode_change_event_reader.read().next().is_none() {
343        return;
344    }
345
346    // Real-time direct light is used on the scenery if we're using mixed
347    // indirect or real-time mode.
348    let scenery_is_lit_in_real_time = matches!(
349        app_status.lighting_mode,
350        LightingMode::MixedIndirect | LightingMode::RealTime
351    );
352
353    for mut light in &mut lights {
354        light.affects_lightmapped_mesh_diffuse = scenery_is_lit_in_real_time;
355        // Don't bother enabling shadows if they won't show up on the scenery.
356        light.shadows_enabled = scenery_is_lit_in_real_time;
357    }
358}
359
360/// Updates the state of the selection widgets at the bottom of the window when
361/// the lighting mode changes.
362fn update_radio_buttons(
363    mut widgets: Query<
364        (
365            Entity,
366            Option<&mut BackgroundColor>,
367            Has<Text>,
368            &WidgetClickSender<LightingMode>,
369        ),
370        Or<(With<RadioButton>, With<RadioButtonText>)>,
371    >,
372    app_status: Res<AppStatus>,
373    mut writer: TextUiWriter,
374) {
375    for (entity, image, has_text, sender) in &mut widgets {
376        let selected = **sender == app_status.lighting_mode;
377
378        if let Some(mut bg_color) = image {
379            widgets::update_ui_radio_button(&mut bg_color, selected);
380        }
381        if has_text {
382            widgets::update_ui_radio_button_text(entity, &mut writer, selected);
383        }
384    }
385}
386
387/// Handles clicks on the widgets at the bottom of the screen and fires
388/// [`LightingModeChanged`] events.
389fn handle_lighting_mode_change(
390    mut widget_click_event_reader: EventReader<WidgetClickEvent<LightingMode>>,
391    mut lighting_mode_change_event_writer: EventWriter<LightingModeChanged>,
392    mut app_status: ResMut<AppStatus>,
393) {
394    for event in widget_click_event_reader.read() {
395        app_status.lighting_mode = **event;
396        lighting_mode_change_event_writer.write(LightingModeChanged);
397    }
398}
399
400/// Moves the sphere to its original position when the user selects the baked
401/// lighting mode.
402///
403/// As the light from the sphere is precomputed and depends on the sphere's
404/// original position, the sphere must be placed there in order for the lighting
405/// to be correct.
406fn reset_sphere_position(
407    mut objects: Query<(&Name, &mut Transform)>,
408    mut lighting_mode_change_event_reader: EventReader<LightingModeChanged>,
409    app_status: Res<AppStatus>,
410) {
411    // Only run if the lighting mode changed and if the lighting mode is
412    // `LightingMode::Baked`. (Note that a change event is fired when the scene
413    // first loads.)
414    if lighting_mode_change_event_reader.read().next().is_none()
415        || app_status.lighting_mode != LightingMode::Baked
416    {
417        return;
418    }
419
420    for (name, mut transform) in &mut objects {
421        if &**name == "Sphere" {
422            transform.translation = INITIAL_SPHERE_POSITION;
423            break;
424        }
425    }
426}
427
428/// Updates the position of the sphere when the user clicks on a spot in the
429/// scene.
430///
431/// Note that the position of the sphere is locked in baked lighting mode.
432fn move_sphere(
433    mouse_button_input: Res<ButtonInput<MouseButton>>,
434    pointers: Query<&PointerInteraction>,
435    mut meshes: Query<(&Name, &ChildOf), With<Mesh3d>>,
436    mut transforms: Query<&mut Transform>,
437    app_status: Res<AppStatus>,
438) {
439    // Only run when the left button is clicked and we're not in baked lighting
440    // mode.
441    if app_status.lighting_mode == LightingMode::Baked
442        || !mouse_button_input.pressed(MouseButton::Left)
443    {
444        return;
445    }
446
447    // Find the sphere.
448    let Some(child_of) = meshes
449        .iter_mut()
450        .filter_map(|(name, child_of)| {
451            if &**name == "Sphere" {
452                Some(child_of)
453            } else {
454                None
455            }
456        })
457        .next()
458    else {
459        return;
460    };
461
462    // Grab its transform.
463    let Ok(mut transform) = transforms.get_mut(child_of.parent()) else {
464        return;
465    };
466
467    // Set its transform to the appropriate position, as determined by the
468    // picking subsystem.
469    for interaction in pointers.iter() {
470        if let Some(&(
471            _,
472            HitData {
473                position: Some(position),
474                ..
475            },
476        )) = interaction.get_nearest_hit()
477        {
478            transform.translation = position + vec3(0.0, SPHERE_OFFSET, 0.0);
479        }
480    }
481}
482
483/// Changes the help text at the top of the screen when the lighting mode
484/// changes.
485fn adjust_help_text(
486    mut commands: Commands,
487    help_texts: Query<Entity, With<HelpText>>,
488    app_status: Res<AppStatus>,
489    mut lighting_mode_change_event_reader: EventReader<LightingModeChanged>,
490) {
491    if lighting_mode_change_event_reader.read().next().is_none() {
492        return;
493    }
494
495    for help_text in &help_texts {
496        commands
497            .entity(help_text)
498            .insert(create_help_text(&app_status));
499    }
500}
More examples
Hide additional examples
examples/3d/clustered_decals.rs (line 215)
212fn spawn_camera(commands: &mut Commands) {
213    commands
214        .spawn(Camera3d::default())
215        .insert(Transform::from_xyz(0.0, 2.5, 9.0).looking_at(Vec3::ZERO, Vec3::Y))
216        // Tag the camera with `Selection::Camera`.
217        .insert(Selection::Camera);
218}
219
220/// Spawns the actual clustered decals.
221fn spawn_decals(commands: &mut Commands, asset_server: &AssetServer) {
222    let image = asset_server.load("branding/icon.png");
223
224    commands.spawn((
225        ClusteredDecal {
226            image: image.clone(),
227            // Tint with red.
228            tag: 1,
229        },
230        calculate_initial_decal_transform(vec3(1.0, 3.0, 5.0), Vec3::ZERO, Vec2::splat(1.1)),
231        Selection::DecalA,
232    ));
233
234    commands.spawn((
235        ClusteredDecal {
236            image: image.clone(),
237            // Tint with blue.
238            tag: 2,
239        },
240        calculate_initial_decal_transform(vec3(-2.0, -1.0, 4.0), Vec3::ZERO, Vec2::splat(2.0)),
241        Selection::DecalB,
242    ));
243}
244
245/// Spawns the buttons at the bottom of the screen.
246fn spawn_buttons(commands: &mut Commands) {
247    // Spawn the radio buttons that allow the user to select an object to
248    // control.
249    commands
250        .spawn(widgets::main_ui_node())
251        .with_children(|parent| {
252            widgets::spawn_option_buttons(
253                parent,
254                "Drag to Move",
255                &[
256                    (Selection::Camera, "Camera"),
257                    (Selection::DecalA, "Decal A"),
258                    (Selection::DecalB, "Decal B"),
259                ],
260            );
261        });
262
263    // Spawn the drag buttons that allow the user to control the scale and roll
264    // of the selected object.
265    commands
266        .spawn(Node {
267            flex_direction: FlexDirection::Row,
268            position_type: PositionType::Absolute,
269            right: Val::Px(10.0),
270            bottom: Val::Px(10.0),
271            column_gap: Val::Px(6.0),
272            ..default()
273        })
274        .with_children(|parent| {
275            spawn_drag_button(parent, "Scale").insert(DragMode::Scale);
276            spawn_drag_button(parent, "Roll").insert(DragMode::Roll);
277        });
278}
279
280/// Spawns a button that the user can drag to change a parameter.
281fn spawn_drag_button<'a>(
282    commands: &'a mut ChildSpawnerCommands,
283    label: &str,
284) -> EntityCommands<'a> {
285    let mut kid = commands.spawn(Node {
286        border: BUTTON_BORDER,
287        justify_content: JustifyContent::Center,
288        align_items: AlignItems::Center,
289        padding: BUTTON_PADDING,
290        ..default()
291    });
292    kid.insert((
293        Button,
294        BackgroundColor(Color::BLACK),
295        BorderRadius::all(BUTTON_BORDER_RADIUS_SIZE),
296        BUTTON_BORDER_COLOR,
297    ))
298    .with_children(|parent| {
299        widgets::spawn_ui_text(parent, label, Color::WHITE);
300    });
301    kid
302}
303
304/// Spawns the help text at the top of the screen.
305fn spawn_help_text(commands: &mut Commands, app_status: &AppStatus) {
306    commands.spawn((
307        Text::new(create_help_string(app_status)),
308        Node {
309            position_type: PositionType::Absolute,
310            top: Val::Px(12.0),
311            left: Val::Px(12.0),
312            ..default()
313        },
314        HelpText,
315    ));
316}
317
318/// Draws the outlines that show the bounds of the clustered decals.
319fn draw_gizmos(
320    mut gizmos: Gizmos,
321    decals: Query<(&GlobalTransform, &Selection), With<ClusteredDecal>>,
322) {
323    for (global_transform, selection) in &decals {
324        let color = match *selection {
325            Selection::Camera => continue,
326            Selection::DecalA => ORANGE_RED,
327            Selection::DecalB => LIME,
328        };
329
330        gizmos.primitive_3d(
331            &Cuboid {
332                // Since the clustered decal is a 1×1×1 cube in model space, its
333                // half-size is half of the scaling part of its transform.
334                half_size: global_transform.scale() * 0.5,
335            },
336            Isometry3d {
337                rotation: global_transform.rotation(),
338                translation: global_transform.translation_vec3a(),
339            },
340            color,
341        );
342    }
343}
344
345/// Calculates the initial transform of the clustered decal.
346fn calculate_initial_decal_transform(start: Vec3, looking_at: Vec3, size: Vec2) -> Transform {
347    let direction = looking_at - start;
348    let center = start + direction * 0.5;
349    Transform::from_translation(center)
350        .with_scale((size * 0.5).extend(direction.length()))
351        .looking_to(direction, Vec3::Y)
352}
353
354/// Rotates the cube a bit every frame.
355fn rotate_cube(mut meshes: Query<&mut Transform, With<Mesh3d>>) {
356    for mut transform in &mut meshes {
357        transform.rotate_y(CUBE_ROTATION_SPEED);
358    }
359}
360
361/// Updates the state of the radio buttons when the user clicks on one.
362fn update_radio_buttons(
363    mut widgets: Query<(
364        Entity,
365        Option<&mut BackgroundColor>,
366        Has<Text>,
367        &WidgetClickSender<Selection>,
368    )>,
369    app_status: Res<AppStatus>,
370    mut writer: TextUiWriter,
371) {
372    for (entity, maybe_bg_color, has_text, sender) in &mut widgets {
373        let selected = app_status.selection == **sender;
374        if let Some(mut bg_color) = maybe_bg_color {
375            widgets::update_ui_radio_button(&mut bg_color, selected);
376        }
377        if has_text {
378            widgets::update_ui_radio_button_text(entity, &mut writer, selected);
379        }
380    }
381}
382
383/// Changes the selection when the user clicks a radio button.
384fn handle_selection_change(
385    mut events: EventReader<WidgetClickEvent<Selection>>,
386    mut app_status: ResMut<AppStatus>,
387) {
388    for event in events.read() {
389        app_status.selection = **event;
390    }
391}
392
393/// Process a drag event that moves the selected object.
394fn process_move_input(
395    mut selections: Query<(&mut Transform, &Selection)>,
396    mouse_buttons: Res<ButtonInput<MouseButton>>,
397    mouse_motion: Res<AccumulatedMouseMotion>,
398    app_status: Res<AppStatus>,
399) {
400    // Only process drags when movement is selected.
401    if !mouse_buttons.pressed(MouseButton::Left) || app_status.drag_mode != DragMode::Move {
402        return;
403    }
404
405    for (mut transform, selection) in &mut selections {
406        if app_status.selection != *selection {
407            continue;
408        }
409
410        let position = transform.translation;
411
412        // Convert to spherical coordinates.
413        let radius = position.length();
414        let mut theta = acos(position.y / radius);
415        let mut phi = position.z.signum() * acos(position.x * position.xz().length_recip());
416
417        // Camera movement is the inverse of object movement.
418        let (phi_factor, theta_factor) = match *selection {
419            Selection::Camera => (1.0, -1.0),
420            Selection::DecalA | Selection::DecalB => (-1.0, 1.0),
421        };
422
423        // Adjust the spherical coordinates. Clamp the inclination to (0, π).
424        phi += phi_factor * mouse_motion.delta.x * MOVE_SPEED;
425        theta = f32::clamp(
426            theta + theta_factor * mouse_motion.delta.y * MOVE_SPEED,
427            0.001,
428            PI - 0.001,
429        );
430
431        // Convert spherical coordinates back to Cartesian coordinates.
432        transform.translation =
433            radius * vec3(sin(theta) * cos(phi), cos(theta), sin(theta) * sin(phi));
434
435        // Look at the center, but preserve the previous roll angle.
436        let roll = transform.rotation.to_euler(EulerRot::YXZ).2;
437        transform.look_at(Vec3::ZERO, Vec3::Y);
438        let (yaw, pitch, _) = transform.rotation.to_euler(EulerRot::YXZ);
439        transform.rotation = Quat::from_euler(EulerRot::YXZ, yaw, pitch, roll);
440    }
441}
442
443/// Processes a drag event that scales the selected target.
444fn process_scale_input(
445    mut selections: Query<(&mut Transform, &Selection)>,
446    mouse_buttons: Res<ButtonInput<MouseButton>>,
447    mouse_motion: Res<AccumulatedMouseMotion>,
448    app_status: Res<AppStatus>,
449) {
450    // Only process drags when the scaling operation is selected.
451    if !mouse_buttons.pressed(MouseButton::Left) || app_status.drag_mode != DragMode::Scale {
452        return;
453    }
454
455    for (mut transform, selection) in &mut selections {
456        if app_status.selection == *selection {
457            transform.scale *= 1.0 + mouse_motion.delta.x * SCALE_SPEED;
458        }
459    }
460}
461
462/// Processes a drag event that rotates the selected target along its local Z
463/// axis.
464fn process_roll_input(
465    mut selections: Query<(&mut Transform, &Selection)>,
466    mouse_buttons: Res<ButtonInput<MouseButton>>,
467    mouse_motion: Res<AccumulatedMouseMotion>,
468    app_status: Res<AppStatus>,
469) {
470    // Only process drags when the rolling operation is selected.
471    if !mouse_buttons.pressed(MouseButton::Left) || app_status.drag_mode != DragMode::Roll {
472        return;
473    }
474
475    for (mut transform, selection) in &mut selections {
476        if app_status.selection != *selection {
477            continue;
478        }
479
480        let (yaw, pitch, mut roll) = transform.rotation.to_euler(EulerRot::YXZ);
481        roll += mouse_motion.delta.x * ROLL_SPEED;
482        transform.rotation = Quat::from_euler(EulerRot::YXZ, yaw, pitch, roll);
483    }
484}
485
486/// Creates the help string at the top left of the screen.
487fn create_help_string(app_status: &AppStatus) -> String {
488    format!(
489        "Click and drag to {} {}",
490        app_status.drag_mode, app_status.selection
491    )
492}
493
494/// Changes the drag mode when the user hovers over the "Scale" and "Roll"
495/// buttons in the lower right.
496///
497/// If the user is hovering over no such button, this system changes the drag
498/// mode back to its default value of [`DragMode::Move`].
499fn switch_drag_mode(
500    mut commands: Commands,
501    mut interactions: Query<(&Interaction, &DragMode)>,
502    mut windows: Query<Entity, With<Window>>,
503    mouse_buttons: Res<ButtonInput<MouseButton>>,
504    mut app_status: ResMut<AppStatus>,
505) {
506    if mouse_buttons.pressed(MouseButton::Left) {
507        return;
508    }
509
510    for (interaction, drag_mode) in &mut interactions {
511        if *interaction != Interaction::Hovered {
512            continue;
513        }
514
515        app_status.drag_mode = *drag_mode;
516
517        // Set the cursor to provide the user with a nice visual hint.
518        for window in &mut windows {
519            commands
520                .entity(window)
521                .insert(CursorIcon::from(SystemCursorIcon::EwResize));
522        }
523        return;
524    }
525
526    app_status.drag_mode = DragMode::Move;
527
528    for window in &mut windows {
529        commands.entity(window).remove::<CursorIcon>();
530    }
531}
examples/3d/irradiance_volumes.rs (line 276)
269fn spawn_sphere(commands: &mut Commands, assets: &ExampleAssets) {
270    commands
271        .spawn((
272            Mesh3d(assets.main_sphere.clone()),
273            MeshMaterial3d(assets.main_sphere_material.clone()),
274            Transform::from_xyz(0.0, SPHERE_SCALE, 0.0).with_scale(Vec3::splat(SPHERE_SCALE)),
275        ))
276        .insert(MainObject);
277}
278
279fn spawn_voxel_cube_parent(commands: &mut Commands) {
280    commands.spawn((Visibility::Hidden, Transform::default(), VoxelCubeParent));
281}
282
283fn spawn_fox(commands: &mut Commands, assets: &ExampleAssets) {
284    commands.spawn((
285        SceneRoot(assets.fox.clone()),
286        Visibility::Hidden,
287        Transform::from_scale(Vec3::splat(FOX_SCALE)),
288        MainObject,
289    ));
290}
291
292fn spawn_text(commands: &mut Commands, app_status: &AppStatus) {
293    commands.spawn((
294        app_status.create_text(),
295        Node {
296            position_type: PositionType::Absolute,
297            bottom: Val::Px(12.0),
298            left: Val::Px(12.0),
299            ..default()
300        },
301    ));
302}
303
304// A system that updates the help text.
305fn update_text(mut text_query: Query<&mut Text>, app_status: Res<AppStatus>) {
306    for mut text in text_query.iter_mut() {
307        *text = app_status.create_text();
308    }
309}
310
311impl AppStatus {
312    // Constructs the help text at the bottom of the screen based on the
313    // application status.
314    fn create_text(&self) -> Text {
315        let irradiance_volume_help_text = if self.irradiance_volume_present {
316            DISABLE_IRRADIANCE_VOLUME_HELP_TEXT
317        } else {
318            ENABLE_IRRADIANCE_VOLUME_HELP_TEXT
319        };
320
321        let voxels_help_text = if self.voxels_visible {
322            HIDE_VOXELS_HELP_TEXT
323        } else {
324            SHOW_VOXELS_HELP_TEXT
325        };
326
327        let rotation_help_text = if self.rotating {
328            STOP_ROTATION_HELP_TEXT
329        } else {
330            START_ROTATION_HELP_TEXT
331        };
332
333        let switch_mesh_help_text = match self.model {
334            ExampleModel::Sphere => SWITCH_TO_FOX_HELP_TEXT,
335            ExampleModel::Fox => SWITCH_TO_SPHERE_HELP_TEXT,
336        };
337
338        format!(
339            "{CLICK_TO_MOVE_HELP_TEXT}\n\
340            {voxels_help_text}\n\
341            {irradiance_volume_help_text}\n\
342            {rotation_help_text}\n\
343            {switch_mesh_help_text}"
344        )
345        .into()
346    }
347}
348
349// Rotates the camera a bit every frame.
350fn rotate_camera(
351    mut camera_query: Query<&mut Transform, With<Camera3d>>,
352    time: Res<Time>,
353    app_status: Res<AppStatus>,
354) {
355    if !app_status.rotating {
356        return;
357    }
358
359    for mut transform in camera_query.iter_mut() {
360        transform.translation = Vec2::from_angle(ROTATION_SPEED * time.delta_secs())
361            .rotate(transform.translation.xz())
362            .extend(transform.translation.y)
363            .xzy();
364        transform.look_at(Vec3::ZERO, Vec3::Y);
365    }
366}
367
368// Toggles between the unskinned sphere model and the skinned fox model if the
369// user requests it.
370fn change_main_object(
371    keyboard: Res<ButtonInput<KeyCode>>,
372    mut app_status: ResMut<AppStatus>,
373    mut sphere_query: Query<&mut Visibility, (With<MainObject>, With<Mesh3d>, Without<SceneRoot>)>,
374    mut fox_query: Query<&mut Visibility, (With<MainObject>, With<SceneRoot>)>,
375) {
376    if !keyboard.just_pressed(KeyCode::Tab) {
377        return;
378    }
379    let Some(mut sphere_visibility) = sphere_query.iter_mut().next() else {
380        return;
381    };
382    let Some(mut fox_visibility) = fox_query.iter_mut().next() else {
383        return;
384    };
385
386    match app_status.model {
387        ExampleModel::Sphere => {
388            *sphere_visibility = Visibility::Hidden;
389            *fox_visibility = Visibility::Visible;
390            app_status.model = ExampleModel::Fox;
391        }
392        ExampleModel::Fox => {
393            *sphere_visibility = Visibility::Visible;
394            *fox_visibility = Visibility::Hidden;
395            app_status.model = ExampleModel::Sphere;
396        }
397    }
398}
399
400impl Default for AppStatus {
401    fn default() -> Self {
402        Self {
403            irradiance_volume_present: true,
404            rotating: true,
405            model: ExampleModel::Sphere,
406            voxels_visible: false,
407        }
408    }
409}
410
411// Turns on and off the irradiance volume as requested by the user.
412fn toggle_irradiance_volumes(
413    mut commands: Commands,
414    keyboard: Res<ButtonInput<KeyCode>>,
415    light_probe_query: Query<Entity, With<LightProbe>>,
416    mut app_status: ResMut<AppStatus>,
417    assets: Res<ExampleAssets>,
418    mut ambient_light: ResMut<AmbientLight>,
419) {
420    if !keyboard.just_pressed(KeyCode::Space) {
421        return;
422    };
423
424    let Some(light_probe) = light_probe_query.iter().next() else {
425        return;
426    };
427
428    if app_status.irradiance_volume_present {
429        commands.entity(light_probe).remove::<IrradianceVolume>();
430        ambient_light.brightness = AMBIENT_LIGHT_BRIGHTNESS * IRRADIANCE_VOLUME_INTENSITY;
431        app_status.irradiance_volume_present = false;
432    } else {
433        commands.entity(light_probe).insert(IrradianceVolume {
434            voxels: assets.irradiance_volume.clone(),
435            intensity: IRRADIANCE_VOLUME_INTENSITY,
436            ..default()
437        });
438        ambient_light.brightness = 0.0;
439        app_status.irradiance_volume_present = true;
440    }
441}
442
443fn toggle_rotation(keyboard: Res<ButtonInput<KeyCode>>, mut app_status: ResMut<AppStatus>) {
444    if keyboard.just_pressed(KeyCode::Enter) {
445        app_status.rotating = !app_status.rotating;
446    }
447}
448
449// Handles clicks on the plane that reposition the object.
450fn handle_mouse_clicks(
451    buttons: Res<ButtonInput<MouseButton>>,
452    windows: Query<&Window, With<PrimaryWindow>>,
453    cameras: Query<(&Camera, &GlobalTransform)>,
454    mut main_objects: Query<&mut Transform, With<MainObject>>,
455) {
456    if !buttons.pressed(MouseButton::Left) {
457        return;
458    }
459    let Some(mouse_position) = windows.iter().next().and_then(Window::cursor_position) else {
460        return;
461    };
462    let Some((camera, camera_transform)) = cameras.iter().next() else {
463        return;
464    };
465
466    // Figure out where the user clicked on the plane.
467    let Ok(ray) = camera.viewport_to_world(camera_transform, mouse_position) else {
468        return;
469    };
470    let Some(ray_distance) = ray.intersect_plane(Vec3::ZERO, InfinitePlane3d::new(Vec3::Y)) else {
471        return;
472    };
473    let plane_intersection = ray.origin + ray.direction.normalize() * ray_distance;
474
475    // Move all the main objects.
476    for mut transform in main_objects.iter_mut() {
477        transform.translation = vec3(
478            plane_intersection.x,
479            transform.translation.y,
480            plane_intersection.z,
481        );
482    }
483}
484
485impl FromWorld for ExampleAssets {
486    fn from_world(world: &mut World) -> Self {
487        let fox_animation =
488            world.load_asset(GltfAssetLabel::Animation(1).from_asset("models/animated/Fox.glb"));
489        let (fox_animation_graph, fox_animation_node) =
490            AnimationGraph::from_clip(fox_animation.clone());
491
492        ExampleAssets {
493            main_sphere: world.add_asset(Sphere::default().mesh().uv(32, 18)),
494            fox: world.load_asset(GltfAssetLabel::Scene(0).from_asset("models/animated/Fox.glb")),
495            main_sphere_material: world.add_asset(Color::from(SILVER)),
496            main_scene: world.load_asset(
497                GltfAssetLabel::Scene(0)
498                    .from_asset("models/IrradianceVolumeExample/IrradianceVolumeExample.glb"),
499            ),
500            irradiance_volume: world.load_asset("irradiance_volumes/Example.vxgi.ktx2"),
501            fox_animation_graph: world.add_asset(fox_animation_graph),
502            fox_animation_node,
503            voxel_cube: world.add_asset(Cuboid::default()),
504            // Just use a specular map for the skybox since it's not too blurry.
505            // In reality you wouldn't do this--you'd use a real skybox texture--but
506            // reusing the textures like this saves space in the Bevy repository.
507            skybox: world.load_asset("environment_maps/pisa_specular_rgb9e5_zstd.ktx2"),
508        }
509    }
510}
511
512// Plays the animation on the fox.
513fn play_animations(
514    mut commands: Commands,
515    assets: Res<ExampleAssets>,
516    mut players: Query<(Entity, &mut AnimationPlayer), Without<AnimationGraphHandle>>,
517) {
518    for (entity, mut player) in players.iter_mut() {
519        commands
520            .entity(entity)
521            .insert(AnimationGraphHandle(assets.fox_animation_graph.clone()));
522        player.play(assets.fox_animation_node).repeat();
523    }
524}
525
526fn create_cubes(
527    image_assets: Res<Assets<Image>>,
528    mut commands: Commands,
529    irradiance_volumes: Query<(&IrradianceVolume, &GlobalTransform)>,
530    voxel_cube_parents: Query<Entity, With<VoxelCubeParent>>,
531    voxel_cubes: Query<Entity, With<VoxelCube>>,
532    example_assets: Res<ExampleAssets>,
533    mut voxel_visualization_material_assets: ResMut<Assets<VoxelVisualizationMaterial>>,
534) {
535    // If voxel cubes have already been spawned, don't do anything.
536    if !voxel_cubes.is_empty() {
537        return;
538    }
539
540    let Some(voxel_cube_parent) = voxel_cube_parents.iter().next() else {
541        return;
542    };
543
544    for (irradiance_volume, global_transform) in irradiance_volumes.iter() {
545        let Some(image) = image_assets.get(&irradiance_volume.voxels) else {
546            continue;
547        };
548
549        let resolution = image.texture_descriptor.size;
550
551        let voxel_cube_material = voxel_visualization_material_assets.add(ExtendedMaterial {
552            base: StandardMaterial::from(Color::from(RED)),
553            extension: VoxelVisualizationExtension {
554                irradiance_volume_info: VoxelVisualizationIrradianceVolumeInfo {
555                    world_from_voxel: VOXEL_FROM_WORLD.inverse(),
556                    voxel_from_world: VOXEL_FROM_WORLD,
557                    resolution: uvec3(
558                        resolution.width,
559                        resolution.height,
560                        resolution.depth_or_array_layers,
561                    ),
562                    intensity: IRRADIANCE_VOLUME_INTENSITY,
563                },
564            },
565        });
566
567        let scale = vec3(
568            1.0 / resolution.width as f32,
569            1.0 / resolution.height as f32,
570            1.0 / resolution.depth_or_array_layers as f32,
571        );
572
573        // Spawn a cube for each voxel.
574        for z in 0..resolution.depth_or_array_layers {
575            for y in 0..resolution.height {
576                for x in 0..resolution.width {
577                    let uvw = (uvec3(x, y, z).as_vec3() + 0.5) * scale - 0.5;
578                    let pos = global_transform.transform_point(uvw);
579                    let voxel_cube = commands
580                        .spawn((
581                            Mesh3d(example_assets.voxel_cube.clone()),
582                            MeshMaterial3d(voxel_cube_material.clone()),
583                            Transform::from_scale(Vec3::splat(VOXEL_CUBE_SCALE))
584                                .with_translation(pos),
585                        ))
586                        .insert(VoxelCube)
587                        .insert(NotShadowCaster)
588                        .id();
589
590                    commands.entity(voxel_cube_parent).add_child(voxel_cube);
591                }
592            }
593        }
594    }
595}
examples/ecs/one_shot_systems.rs (line 64)
56fn trigger_system(
57    mut commands: Commands,
58    query_a: Single<Entity, With<A>>,
59    query_b: Single<Entity, With<B>>,
60    input: Res<ButtonInput<KeyCode>>,
61) {
62    if input.just_pressed(KeyCode::KeyA) {
63        let entity = *query_a;
64        commands.entity(entity).insert(Triggered);
65    }
66    if input.just_pressed(KeyCode::KeyB) {
67        let entity = *query_b;
68        commands.entity(entity).insert(Triggered);
69    }
70}
examples/3d/reflection_probes.rs (line 177)
169fn add_environment_map_to_camera(
170    mut commands: Commands,
171    query: Query<Entity, Added<Camera3d>>,
172    cubemaps: Res<Cubemaps>,
173) {
174    for camera_entity in query.iter() {
175        commands
176            .entity(camera_entity)
177            .insert(create_camera_environment_map_light(&cubemaps))
178            .insert(Skybox {
179                image: cubemaps.skybox.clone(),
180                brightness: 5000.0,
181                ..default()
182            });
183    }
184}
185
186// A system that handles switching between different reflection modes.
187fn change_reflection_type(
188    mut commands: Commands,
189    light_probe_query: Query<Entity, With<LightProbe>>,
190    camera_query: Query<Entity, With<Camera3d>>,
191    keyboard: Res<ButtonInput<KeyCode>>,
192    mut app_status: ResMut<AppStatus>,
193    cubemaps: Res<Cubemaps>,
194) {
195    // Only do anything if space was pressed.
196    if !keyboard.just_pressed(KeyCode::Space) {
197        return;
198    }
199
200    // Switch reflection mode.
201    app_status.reflection_mode =
202        ReflectionMode::try_from((app_status.reflection_mode as u32 + 1) % 3).unwrap();
203
204    // Add or remove the light probe.
205    for light_probe in light_probe_query.iter() {
206        commands.entity(light_probe).despawn();
207    }
208    match app_status.reflection_mode {
209        ReflectionMode::None | ReflectionMode::EnvironmentMap => {}
210        ReflectionMode::ReflectionProbe => spawn_reflection_probe(&mut commands, &cubemaps),
211    }
212
213    // Add or remove the environment map from the camera.
214    for camera in camera_query.iter() {
215        match app_status.reflection_mode {
216            ReflectionMode::None => {
217                commands.entity(camera).remove::<EnvironmentMapLight>();
218            }
219            ReflectionMode::EnvironmentMap | ReflectionMode::ReflectionProbe => {
220                commands
221                    .entity(camera)
222                    .insert(create_camera_environment_map_light(&cubemaps));
223            }
224        }
225    }
226}
examples/window/screenshot.rs (line 44)
32fn screenshot_saving(
33    mut commands: Commands,
34    screenshot_saving: Query<Entity, With<Capturing>>,
35    window: Single<Entity, With<Window>>,
36) {
37    match screenshot_saving.iter().count() {
38        0 => {
39            commands.entity(*window).remove::<CursorIcon>();
40        }
41        x if x > 0 => {
42            commands
43                .entity(*window)
44                .insert(CursorIcon::from(SystemCursorIcon::Progress));
45        }
46        _ => {}
47    }
48}
Source

pub fn insert_if<F>( &mut self, bundle: impl Bundle, condition: F, ) -> &mut EntityCommands<'a>
where F: FnOnce() -> bool,

Adds a Bundle of components to the entity if the predicate returns true.

This is useful for chaining method calls.

§Example
#[derive(Component)]
struct StillLoadingStats;
#[derive(Component)]
struct Health(u32);

fn add_health_system(mut commands: Commands, player: Res<PlayerEntity>) {
    commands
        .entity(player.entity)
        .insert_if(Health(10), || !player.is_spectator())
        .remove::<StillLoadingStats>();
}
Examples found in repository?
examples/3d/motion_blur.rs (line 148)
105fn spawn_cars(
106    asset_server: &AssetServer,
107    meshes: &mut Assets<Mesh>,
108    materials: &mut Assets<StandardMaterial>,
109    commands: &mut Commands,
110) {
111    const N_CARS: usize = 20;
112    let box_mesh = meshes.add(Cuboid::new(0.3, 0.15, 0.55));
113    let cylinder = meshes.add(Cylinder::default());
114    let logo = asset_server.load("branding/icon.png");
115    let wheel_matl = materials.add(StandardMaterial {
116        base_color: Color::WHITE,
117        base_color_texture: Some(logo.clone()),
118        ..default()
119    });
120
121    let mut matl = |color| {
122        materials.add(StandardMaterial {
123            base_color: color,
124            ..default()
125        })
126    };
127
128    let colors = [
129        matl(Color::linear_rgb(1.0, 0.0, 0.0)),
130        matl(Color::linear_rgb(1.0, 1.0, 0.0)),
131        matl(Color::BLACK),
132        matl(Color::linear_rgb(0.0, 0.0, 1.0)),
133        matl(Color::linear_rgb(0.0, 1.0, 0.0)),
134        matl(Color::linear_rgb(1.0, 0.0, 1.0)),
135        matl(Color::linear_rgb(0.5, 0.5, 0.0)),
136        matl(Color::linear_rgb(1.0, 0.5, 0.0)),
137    ];
138
139    for i in 0..N_CARS {
140        let color = colors[i % colors.len()].clone();
141        commands
142            .spawn((
143                Mesh3d(box_mesh.clone()),
144                MeshMaterial3d(color.clone()),
145                Transform::from_scale(Vec3::splat(0.5)),
146                Moves(i as f32 * 2.0),
147            ))
148            .insert_if(CameraTracked, || i == 0)
149            .with_children(|parent| {
150                parent.spawn((
151                    Mesh3d(box_mesh.clone()),
152                    MeshMaterial3d(color),
153                    Transform::from_xyz(0.0, 0.08, 0.03).with_scale(Vec3::new(1.0, 1.0, 0.5)),
154                ));
155                let mut spawn_wheel = |x: f32, z: f32| {
156                    parent.spawn((
157                        Mesh3d(cylinder.clone()),
158                        MeshMaterial3d(wheel_matl.clone()),
159                        Transform::from_xyz(0.14 * x, -0.045, 0.15 * z)
160                            .with_scale(Vec3::new(0.15, 0.04, 0.15))
161                            .with_rotation(Quat::from_rotation_z(std::f32::consts::FRAC_PI_2)),
162                        Rotates,
163                    ));
164                };
165                spawn_wheel(1.0, 1.0);
166                spawn_wheel(1.0, -1.0);
167                spawn_wheel(-1.0, 1.0);
168                spawn_wheel(-1.0, -1.0);
169            });
170    }
171}
More examples
Hide additional examples
examples/3d/ssao.rs (lines 114-120)
92fn update(
93    camera: Single<
94        (
95            Entity,
96            Option<&ScreenSpaceAmbientOcclusion>,
97            Option<&TemporalJitter>,
98        ),
99        With<Camera>,
100    >,
101    mut text: Single<&mut Text>,
102    mut sphere: Single<&mut Transform, With<SphereMarker>>,
103    mut commands: Commands,
104    keycode: Res<ButtonInput<KeyCode>>,
105    time: Res<Time>,
106) {
107    sphere.translation.y = ops::sin(time.elapsed_secs() / 1.7) * 0.7;
108
109    let (camera_entity, ssao, temporal_jitter) = *camera;
110    let current_ssao = ssao.cloned().unwrap_or_default();
111
112    let mut commands = commands.entity(camera_entity);
113    commands
114        .insert_if(
115            ScreenSpaceAmbientOcclusion {
116                quality_level: ScreenSpaceAmbientOcclusionQualityLevel::Low,
117                ..current_ssao
118            },
119            || keycode.just_pressed(KeyCode::Digit2),
120        )
121        .insert_if(
122            ScreenSpaceAmbientOcclusion {
123                quality_level: ScreenSpaceAmbientOcclusionQualityLevel::Medium,
124                ..current_ssao
125            },
126            || keycode.just_pressed(KeyCode::Digit3),
127        )
128        .insert_if(
129            ScreenSpaceAmbientOcclusion {
130                quality_level: ScreenSpaceAmbientOcclusionQualityLevel::High,
131                ..current_ssao
132            },
133            || keycode.just_pressed(KeyCode::Digit4),
134        )
135        .insert_if(
136            ScreenSpaceAmbientOcclusion {
137                quality_level: ScreenSpaceAmbientOcclusionQualityLevel::Ultra,
138                ..current_ssao
139            },
140            || keycode.just_pressed(KeyCode::Digit5),
141        )
142        .insert_if(
143            ScreenSpaceAmbientOcclusion {
144                constant_object_thickness: (current_ssao.constant_object_thickness * 2.0).min(4.0),
145                ..current_ssao
146            },
147            || keycode.just_pressed(KeyCode::ArrowUp),
148        )
149        .insert_if(
150            ScreenSpaceAmbientOcclusion {
151                constant_object_thickness: (current_ssao.constant_object_thickness * 0.5)
152                    .max(0.0625),
153                ..current_ssao
154            },
155            || keycode.just_pressed(KeyCode::ArrowDown),
156        );
157    if keycode.just_pressed(KeyCode::Digit1) {
158        commands.remove::<ScreenSpaceAmbientOcclusion>();
159    }
160    if keycode.just_pressed(KeyCode::Space) {
161        if temporal_jitter.is_some() {
162            commands.remove::<TemporalJitter>();
163        } else {
164            commands.insert(TemporalJitter::default());
165        }
166    }
167
168    text.clear();
169
170    let (o, l, m, h, u) = match ssao.map(|s| s.quality_level) {
171        None => ("*", "", "", "", ""),
172        Some(ScreenSpaceAmbientOcclusionQualityLevel::Low) => ("", "*", "", "", ""),
173        Some(ScreenSpaceAmbientOcclusionQualityLevel::Medium) => ("", "", "*", "", ""),
174        Some(ScreenSpaceAmbientOcclusionQualityLevel::High) => ("", "", "", "*", ""),
175        Some(ScreenSpaceAmbientOcclusionQualityLevel::Ultra) => ("", "", "", "", "*"),
176        _ => unreachable!(),
177    };
178
179    if let Some(thickness) = ssao.map(|s| s.constant_object_thickness) {
180        text.push_str(&format!(
181            "Constant object thickness: {} (Up/Down)\n\n",
182            thickness
183        ));
184    }
185
186    text.push_str("SSAO Quality:\n");
187    text.push_str(&format!("(1) {o}Off{o}\n"));
188    text.push_str(&format!("(2) {l}Low{l}\n"));
189    text.push_str(&format!("(3) {m}Medium{m}\n"));
190    text.push_str(&format!("(4) {h}High{h}\n"));
191    text.push_str(&format!("(5) {u}Ultra{u}\n\n"));
192
193    text.push_str("Temporal Antialiasing:\n");
194    text.push_str(match temporal_jitter {
195        Some(_) => "(Space) Enabled",
196        None => "(Space) Disabled",
197    });
198}
examples/stress_tests/many_cubes.rs (line 180)
137fn setup(
138    mut commands: Commands,
139    args: Res<Args>,
140    mesh_assets: ResMut<Assets<Mesh>>,
141    material_assets: ResMut<Assets<StandardMaterial>>,
142    images: ResMut<Assets<Image>>,
143) {
144    warn!(include_str!("warning_string.txt"));
145
146    let args = args.into_inner();
147    let images = images.into_inner();
148    let material_assets = material_assets.into_inner();
149    let mesh_assets = mesh_assets.into_inner();
150
151    let meshes = init_meshes(args, mesh_assets);
152
153    let material_textures = init_textures(args, images);
154    let materials = init_materials(args, &material_textures, material_assets);
155
156    // We're seeding the PRNG here to make this example deterministic for testing purposes.
157    // This isn't strictly required in practical use unless you need your app to be deterministic.
158    let mut material_rng = ChaCha8Rng::seed_from_u64(42);
159    match args.layout {
160        Layout::Sphere => {
161            // NOTE: This pattern is good for testing performance of culling as it provides roughly
162            // the same number of visible meshes regardless of the viewing angle.
163            const N_POINTS: usize = WIDTH * HEIGHT * 4;
164            // NOTE: f64 is used to avoid precision issues that produce visual artifacts in the distribution
165            let radius = WIDTH as f64 * 2.5;
166            let golden_ratio = 0.5f64 * (1.0f64 + 5.0f64.sqrt());
167            for i in 0..N_POINTS {
168                let spherical_polar_theta_phi =
169                    fibonacci_spiral_on_sphere(golden_ratio, i, N_POINTS);
170                let unit_sphere_p = spherical_polar_to_cartesian(spherical_polar_theta_phi);
171                let (mesh, transform) = meshes.choose(&mut material_rng).unwrap();
172                commands
173                    .spawn((
174                        Mesh3d(mesh.clone()),
175                        MeshMaterial3d(materials.choose(&mut material_rng).unwrap().clone()),
176                        Transform::from_translation((radius * unit_sphere_p).as_vec3())
177                            .looking_at(Vec3::ZERO, Vec3::Y)
178                            .mul_transform(*transform),
179                    ))
180                    .insert_if(NoFrustumCulling, || args.no_frustum_culling)
181                    .insert_if(NoAutomaticBatching, || args.no_automatic_batching);
182            }
183
184            // camera
185            let mut camera = commands.spawn(Camera3d::default());
186            if args.no_indirect_drawing {
187                camera.insert(NoIndirectDrawing);
188            }
189            if args.no_cpu_culling {
190                camera.insert(NoCpuCulling);
191            }
192
193            // Inside-out box around the meshes onto which shadows are cast (though you cannot see them...)
194            commands.spawn((
195                Mesh3d(mesh_assets.add(Cuboid::from_size(Vec3::splat(radius as f32 * 2.2)))),
196                MeshMaterial3d(material_assets.add(StandardMaterial::from(Color::WHITE))),
197                Transform::from_scale(-Vec3::ONE),
198                NotShadowCaster,
199            ));
200        }
201        _ => {
202            // NOTE: This pattern is good for demonstrating that frustum culling is working correctly
203            // as the number of visible meshes rises and falls depending on the viewing angle.
204            let scale = 2.5;
205            for x in 0..WIDTH {
206                for y in 0..HEIGHT {
207                    // introduce spaces to break any kind of moiré pattern
208                    if x % 10 == 0 || y % 10 == 0 {
209                        continue;
210                    }
211                    // cube
212                    commands.spawn((
213                        Mesh3d(meshes.choose(&mut material_rng).unwrap().0.clone()),
214                        MeshMaterial3d(materials.choose(&mut material_rng).unwrap().clone()),
215                        Transform::from_xyz((x as f32) * scale, (y as f32) * scale, 0.0),
216                    ));
217                    commands.spawn((
218                        Mesh3d(meshes.choose(&mut material_rng).unwrap().0.clone()),
219                        MeshMaterial3d(materials.choose(&mut material_rng).unwrap().clone()),
220                        Transform::from_xyz(
221                            (x as f32) * scale,
222                            HEIGHT as f32 * scale,
223                            (y as f32) * scale,
224                        ),
225                    ));
226                    commands.spawn((
227                        Mesh3d(meshes.choose(&mut material_rng).unwrap().0.clone()),
228                        MeshMaterial3d(materials.choose(&mut material_rng).unwrap().clone()),
229                        Transform::from_xyz((x as f32) * scale, 0.0, (y as f32) * scale),
230                    ));
231                    commands.spawn((
232                        Mesh3d(meshes.choose(&mut material_rng).unwrap().0.clone()),
233                        MeshMaterial3d(materials.choose(&mut material_rng).unwrap().clone()),
234                        Transform::from_xyz(0.0, (x as f32) * scale, (y as f32) * scale),
235                    ));
236                }
237            }
238            // camera
239            let center = 0.5 * scale * Vec3::new(WIDTH as f32, HEIGHT as f32, WIDTH as f32);
240            commands.spawn((Camera3d::default(), Transform::from_translation(center)));
241            // Inside-out box around the meshes onto which shadows are cast (though you cannot see them...)
242            commands.spawn((
243                Mesh3d(mesh_assets.add(Cuboid::from_size(2.0 * 1.1 * center))),
244                MeshMaterial3d(material_assets.add(StandardMaterial::from(Color::WHITE))),
245                Transform::from_scale(-Vec3::ONE).with_translation(center),
246                NotShadowCaster,
247            ));
248        }
249    }
250
251    commands.spawn((
252        DirectionalLight {
253            shadows_enabled: args.shadows,
254            ..default()
255        },
256        Transform::IDENTITY.looking_at(Vec3::new(0.0, -1.0, -1.0), Vec3::Y),
257    ));
258}
Source

pub fn insert_if_new(&mut self, bundle: impl Bundle) -> &mut EntityCommands<'a>

Adds a Bundle of components to the entity without overwriting.

This is the same as EntityCommands::insert, but in case of duplicate components will leave the old values instead of replacing them with new ones.

See also entry, which lets you modify a Component if it’s present, as well as initialize it with a default value.

Source

pub fn insert_if_new_and<F>( &mut self, bundle: impl Bundle, condition: F, ) -> &mut EntityCommands<'a>
where F: FnOnce() -> bool,

Adds a Bundle of components to the entity without overwriting if the predicate returns true.

This is the same as EntityCommands::insert_if, but in case of duplicate components will leave the old values instead of replacing them with new ones.

Source

pub unsafe fn insert_by_id<T>( &mut self, component_id: ComponentId, value: T, ) -> &mut EntityCommands<'a>
where T: Send + 'static,

Adds a dynamic Component to the entity.

This will overwrite any previous value(s) of the same component type.

You should prefer to use the typed API EntityCommands::insert where possible.

§Safety
  • ComponentId must be from the same world as self.
  • T must have the same layout as the one passed during component_id creation.
Source

pub unsafe fn try_insert_by_id<T>( &mut self, component_id: ComponentId, value: T, ) -> &mut EntityCommands<'a>
where T: Send + 'static,

Adds a dynamic Component to the entity.

This will overwrite any previous value(s) of the same component type.

You should prefer to use the typed API EntityCommands::try_insert where possible.

§Note

If the entity does not exist when this command is executed, the resulting error will be ignored.

§Safety
  • ComponentId must be from the same world as self.
  • T must have the same layout as the one passed during component_id creation.
Source

pub fn try_insert(&mut self, bundle: impl Bundle) -> &mut EntityCommands<'a>

Adds a Bundle of components to the entity.

This will overwrite any previous value(s) of the same component type.

§Note

If the entity does not exist when this command is executed, the resulting error will be ignored.

§Example
#[derive(Component)]
struct Health(u32);
#[derive(Component)]
struct Strength(u32);
#[derive(Component)]
struct Defense(u32);

#[derive(Bundle)]
struct CombatBundle {
    health: Health,
    strength: Strength,
}

fn add_combat_stats_system(mut commands: Commands, player: Res<PlayerEntity>) {
    commands.entity(player.entity)
        // You can insert individual components:
        .try_insert(Defense(10))
        // You can also insert tuples of components:
        .try_insert(CombatBundle {
            health: Health(100),
            strength: Strength(40),
        });

    // Suppose this occurs in a parallel adjacent system or process.
    commands.entity(player.entity).despawn();

    // This will not panic nor will it add the component.
    commands.entity(player.entity).try_insert(Defense(5));
}
Source

pub fn try_insert_if<F>( &mut self, bundle: impl Bundle, condition: F, ) -> &mut EntityCommands<'a>
where F: FnOnce() -> bool,

Adds a Bundle of components to the entity if the predicate returns true.

This is useful for chaining method calls.

§Note

If the entity does not exist when this command is executed, the resulting error will be ignored.

Source

pub fn try_insert_if_new_and<F>( &mut self, bundle: impl Bundle, condition: F, ) -> &mut EntityCommands<'a>
where F: FnOnce() -> bool,

Adds a Bundle of components to the entity without overwriting if the predicate returns true.

This is the same as EntityCommands::try_insert_if, but in case of duplicate components will leave the old values instead of replacing them with new ones.

§Note

If the entity does not exist when this command is executed, the resulting error will be ignored.

Source

pub fn try_insert_if_new( &mut self, bundle: impl Bundle, ) -> &mut EntityCommands<'a>

Adds a Bundle of components to the entity without overwriting.

This is the same as EntityCommands::try_insert, but in case of duplicate components will leave the old values instead of replacing them with new ones.

§Note

If the entity does not exist when this command is executed, the resulting error will be ignored.

Source

pub fn remove<B>(&mut self) -> &mut EntityCommands<'a>
where B: Bundle,

Removes a Bundle of components from the entity.

This will remove all components that intersect with the provided bundle; the entity does not need to have all the components in the bundle.

This will emit a warning if the entity does not exist.

§Example
#[derive(Component)]
struct Health(u32);
#[derive(Component)]
struct Strength(u32);
#[derive(Component)]
struct Defense(u32);

#[derive(Bundle)]
struct CombatBundle {
    health: Health,
    strength: Strength,
}

fn remove_combat_stats_system(mut commands: Commands, player: Res<PlayerEntity>) {
    commands
        .entity(player.entity)
        // You can remove individual components:
        .remove::<Defense>()
        // You can also remove pre-defined bundles of components:
        .remove::<CombatBundle>()
        // You can also remove tuples of components and bundles.
        // This is equivalent to the calls above:
        .remove::<(Defense, CombatBundle)>();
}
Examples found in repository?
examples/remote/server.rs (line 85)
84fn remove(mut commands: Commands, cube_entity: Single<Entity, With<Cube>>) {
85    commands.entity(*cube_entity).remove::<Cube>();
86}
More examples
Hide additional examples
examples/ecs/one_shot_systems.rs (line 78)
75fn evaluate_callbacks(query: Query<(Entity, &Callback), With<Triggered>>, mut commands: Commands) {
76    for (entity, callback) in query.iter() {
77        commands.run_system(callback.0);
78        commands.entity(entity).remove::<Triggered>();
79    }
80}
examples/ecs/removal_detection.rs (line 46)
38fn remove_component(
39    time: Res<Time>,
40    mut commands: Commands,
41    query: Query<Entity, With<MyComponent>>,
42) {
43    // After two seconds have passed the `Component` is removed.
44    if time.elapsed_secs() > 2.0 {
45        if let Some(entity) = query.iter().next() {
46            commands.entity(entity).remove::<MyComponent>();
47        }
48    }
49}
examples/ecs/component_hooks.rs (line 142)
135fn trigger_hooks(
136    mut commands: Commands,
137    keys: Res<ButtonInput<KeyCode>>,
138    index: Res<MyComponentIndex>,
139) {
140    for (key, entity) in index.iter() {
141        if !keys.pressed(*key) {
142            commands.entity(*entity).remove::<MyComponent>();
143        }
144    }
145    for key in keys.get_just_pressed() {
146        commands.spawn(MyComponent(*key));
147    }
148}
examples/window/screenshot.rs (line 39)
32fn screenshot_saving(
33    mut commands: Commands,
34    screenshot_saving: Query<Entity, With<Capturing>>,
35    window: Single<Entity, With<Window>>,
36) {
37    match screenshot_saving.iter().count() {
38        0 => {
39            commands.entity(*window).remove::<CursorIcon>();
40        }
41        x if x > 0 => {
42            commands
43                .entity(*window)
44                .insert(CursorIcon::from(SystemCursorIcon::Progress));
45        }
46        _ => {}
47    }
48}
examples/audio/soundtrack.rs (line 121)
111fn fade_in(
112    mut commands: Commands,
113    mut audio_sink: Query<(&mut AudioSink, Entity), With<FadeIn>>,
114    time: Res<Time>,
115) {
116    for (mut audio, entity) in audio_sink.iter_mut() {
117        let current_volume = audio.volume();
118        audio.set_volume(current_volume + Volume::Linear(time.delta_secs() / FADE_TIME));
119        if audio.volume().to_linear() >= 1.0 {
120            audio.set_volume(Volume::Linear(1.0));
121            commands.entity(entity).remove::<FadeIn>();
122        }
123    }
124}
Source

pub fn try_remove<B>(&mut self) -> &mut EntityCommands<'a>
where B: Bundle,

Removes a Bundle of components from the entity.

This will remove all components that intersect with the provided bundle; the entity does not need to have all the components in the bundle.

Unlike Self::remove, this will not emit a warning if the entity does not exist.

§Example
#[derive(Component)]
struct Health(u32);
#[derive(Component)]
struct Strength(u32);
#[derive(Component)]
struct Defense(u32);

#[derive(Bundle)]
struct CombatBundle {
    health: Health,
    strength: Strength,
}

fn remove_combat_stats_system(mut commands: Commands, player: Res<PlayerEntity>) {
    commands
        .entity(player.entity)
        // You can remove individual components:
        .try_remove::<Defense>()
        // You can also remove pre-defined bundles of components:
        .try_remove::<CombatBundle>()
        // You can also remove tuples of components and bundles.
        // This is equivalent to the calls above:
        .try_remove::<(Defense, CombatBundle)>();
}
Source

pub fn remove_with_requires<B>(&mut self) -> &mut EntityCommands<'a>
where B: Bundle,

Removes a Bundle of components from the entity, and also removes any components required by the components in the bundle.

This will remove all components that intersect with the provided bundle; the entity does not need to have all the components in the bundle.

§Example
#[derive(Component)]
#[require(B)]
struct A;
#[derive(Component, Default)]
struct B;

fn remove_with_requires_system(mut commands: Commands, player: Res<PlayerEntity>) {
    commands
        .entity(player.entity)
        // Removes both A and B from the entity, because B is required by A.
        .remove_with_requires::<A>();
}
Source

pub fn remove_by_id( &mut self, component_id: ComponentId, ) -> &mut EntityCommands<'a>

Removes a dynamic Component from the entity if it exists.

§Panics

Panics if the provided ComponentId does not exist in the World.

Source

pub fn clear(&mut self) -> &mut EntityCommands<'a>

Removes all components associated with the entity.

Source

pub fn despawn(&mut self)

Despawns the entity.

This will emit a warning if the entity does not exist.

§Note

This will also despawn the entities in any RelationshipTarget that is configured to despawn descendants.

For example, this will recursively despawn Children.

§Example
fn remove_character_system(
    mut commands: Commands,
    character_to_remove: Res<CharacterToRemove>
) {
    commands.entity(character_to_remove.entity).despawn();
}
Examples found in repository?
examples/state/custom_transitions.rs (line 166)
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
Hide additional examples
examples/state/states.rs (line 113)
112fn cleanup_menu(mut commands: Commands, menu_data: Res<MenuData>) {
113    commands.entity(menu_data.button_entity).despawn();
114}
examples/state/sub_states.rs (line 87)
86fn cleanup_menu(mut commands: Commands, menu_data: Res<MenuData>) {
87    commands.entity(menu_data.button_entity).despawn();
88}
examples/state/computed_states.rs (line 407)
406    pub fn cleanup_menu(mut commands: Commands, menu_data: Res<MenuData>) {
407        commands.entity(menu_data.root_entity).despawn();
408    }
examples/stress_tests/many_buttons.rs (line 321)
320fn despawn_ui(mut commands: Commands, root_node: Single<Entity, (With<Node>, Without<ChildOf>)>) {
321    commands.entity(*root_node).despawn();
322}
examples/ecs/generic_system.rs (line 87)
85fn cleanup_system<T: Component>(mut commands: Commands, query: Query<Entity, With<T>>) {
86    for e in &query {
87        commands.entity(e).despawn();
88    }
89}
Source

pub fn despawn_recursive(&mut self)

👎Deprecated since 0.16.0: Use entity.despawn(), which now automatically despawns recursively.

Despawns the provided entity and its descendants.

Source

pub fn try_despawn(&mut self)

Despawns the entity.

Unlike Self::despawn, this will not emit a warning if the entity does not exist.

§Note

This will also despawn the entities in any RelationshipTarget that is configured to despawn descendants.

For example, this will recursively despawn Children.

Source

pub fn queue<C, T, M>(&mut self, command: C) -> &mut EntityCommands<'a>

Pushes an EntityCommand to the queue, which will get executed for the current Entity.

The default error handler will be used to handle error cases. Every EntityCommand checks whether the entity exists at the time of execution and returns an error if it does not.

To use a custom error handler, see EntityCommands::queue_handled.

The command can be:

§Example
commands
    .spawn_empty()
    // Closures with this signature implement `EntityCommand`.
    .queue(|entity: EntityWorldMut| {
        println!("Executed an EntityCommand for {}", entity.id());
    });
Source

pub fn queue_handled<C, T, M>( &mut self, command: C, error_handler: fn(BevyError, ErrorContext), ) -> &mut EntityCommands<'a>

Pushes an EntityCommand to the queue, which will get executed for the current Entity.

The given error_handler will be used to handle error cases. Every EntityCommand checks whether the entity exists at the time of execution and returns an error if it does not.

To implicitly use the default error handler, see EntityCommands::queue.

The command can be:

§Example
use bevy_ecs::error::warn;

commands
    .spawn_empty()
    // Closures with this signature implement `EntityCommand`.
    .queue_handled(
        |entity: EntityWorldMut| -> Result {
            let value: usize = "100".parse()?;
            println!("Successfully parsed the value {} for entity {}", value, entity.id());
            Ok(())
        },
        warn
    );
Source

pub fn retain<B>(&mut self) -> &mut EntityCommands<'a>
where B: Bundle,

Removes all components except the given Bundle from the entity.

§Example
#[derive(Component)]
struct Health(u32);
#[derive(Component)]
struct Strength(u32);
#[derive(Component)]
struct Defense(u32);

#[derive(Bundle)]
struct CombatBundle {
    health: Health,
    strength: Strength,
}

fn remove_combat_stats_system(mut commands: Commands, player: Res<PlayerEntity>) {
    commands
        .entity(player.entity)
        // You can retain a pre-defined Bundle of components,
        // with this removing only the Defense component.
        .retain::<CombatBundle>()
        // You can also retain only a single component.
        .retain::<Health>();
}
Source

pub fn log_components(&mut self) -> &mut EntityCommands<'a>

Logs the components of the entity at the info level.

Source

pub fn commands(&mut self) -> Commands<'_, '_>

Returns the underlying Commands.

Source

pub fn commands_mut(&mut self) -> &mut Commands<'a, 'a>

Returns a mutable reference to the underlying Commands.

Source

pub fn trigger(&mut self, event: impl Event) -> &mut EntityCommands<'a>

Sends a Trigger targeting the entity.

This will run any Observer of the given Event watching this entity.

Source

pub fn observe<E, B, M>( &mut self, observer: impl IntoObserverSystem<E, B, M>, ) -> &mut EntityCommands<'a>
where E: Event, B: Bundle,

Creates an Observer listening for events of type E targeting this entity.

Examples found in repository?
examples/window/screenshot.rs (line 28)
18fn screenshot_on_spacebar(
19    mut commands: Commands,
20    input: Res<ButtonInput<KeyCode>>,
21    mut counter: Local<u32>,
22) {
23    if input.just_pressed(KeyCode::Space) {
24        let path = format!("./screenshot-{}.png", *counter);
25        *counter += 1;
26        commands
27            .spawn(Screenshot::primary_window())
28            .observe(save_to_disk(path));
29    }
30}
More examples
Hide additional examples
examples/ecs/observer_propagation.rs (line 30)
27fn setup(mut commands: Commands) {
28    commands
29        .spawn((Name::new("Goblin"), HitPoints(50)))
30        .observe(take_damage)
31        .with_children(|parent| {
32            parent
33                .spawn((Name::new("Helmet"), Armor(5)))
34                .observe(block_attack);
35            parent
36                .spawn((Name::new("Socks"), Armor(10)))
37                .observe(block_attack);
38            parent
39                .spawn((Name::new("Shirt"), Armor(15)))
40                .observe(block_attack);
41        });
42}
examples/3d/mixed_lighting.rs (lines 173-180)
165fn spawn_scene(commands: &mut Commands, asset_server: &AssetServer) {
166    commands
167        .spawn(SceneRoot(
168            asset_server.load(
169                GltfAssetLabel::Scene(0)
170                    .from_asset("models/MixedLightingExample/MixedLightingExample.gltf"),
171            ),
172        ))
173        .observe(
174            |_: Trigger<SceneInstanceReady>,
175             mut lighting_mode_change_event_writer: EventWriter<LightingModeChanged>| {
176                // When the scene loads, send a `LightingModeChanged` event so
177                // that we set up the lightmaps.
178                lighting_mode_change_event_writer.write(LightingModeChanged);
179            },
180        );
181}
examples/testbed/3d.rs (line 279)
244    pub fn setup(
245        mut commands: Commands,
246        asset_server: Res<AssetServer>,
247        mut graphs: ResMut<Assets<AnimationGraph>>,
248    ) {
249        let (graph, node) = AnimationGraph::from_clip(
250            asset_server.load(GltfAssetLabel::Animation(2).from_asset(FOX_PATH)),
251        );
252
253        let graph_handle = graphs.add(graph);
254        commands.insert_resource(Animation {
255            animation: node,
256            graph: graph_handle,
257        });
258
259        commands.spawn((
260            Camera3d::default(),
261            Transform::from_xyz(100.0, 100.0, 150.0).looking_at(Vec3::new(0.0, 20.0, 0.0), Vec3::Y),
262            StateScoped(CURRENT_SCENE),
263        ));
264
265        commands.spawn((
266            Transform::from_rotation(Quat::from_euler(EulerRot::ZYX, 0.0, 1.0, -PI / 4.)),
267            DirectionalLight {
268                shadows_enabled: true,
269                ..default()
270            },
271            StateScoped(CURRENT_SCENE),
272        ));
273
274        commands
275            .spawn((
276                SceneRoot(asset_server.load(GltfAssetLabel::Scene(0).from_asset(FOX_PATH))),
277                StateScoped(CURRENT_SCENE),
278            ))
279            .observe(pause_animation_frame);
280    }
examples/animation/animated_mesh.rs (line 61)
32fn setup_mesh_and_animation(
33    mut commands: Commands,
34    asset_server: Res<AssetServer>,
35    mut graphs: ResMut<Assets<AnimationGraph>>,
36) {
37    // Create an animation graph containing a single animation. We want the "run"
38    // animation from our example asset, which has an index of two.
39    let (graph, index) = AnimationGraph::from_clip(
40        asset_server.load(GltfAssetLabel::Animation(2).from_asset(GLTF_PATH)),
41    );
42
43    // Store the animation graph as an asset.
44    let graph_handle = graphs.add(graph);
45
46    // Create a component that stores a reference to our animation.
47    let animation_to_play = AnimationToPlay {
48        graph_handle,
49        index,
50    };
51
52    // Start loading the asset as a scene and store a reference to it in a
53    // SceneRoot component. This component will automatically spawn a scene
54    // containing our mesh once it has loaded.
55    let mesh_scene = SceneRoot(asset_server.load(GltfAssetLabel::Scene(0).from_asset(GLTF_PATH)));
56
57    // Spawn an entity with our components, and connect it to an observer that
58    // will trigger when the scene is loaded and spawned.
59    commands
60        .spawn((animation_to_play, mesh_scene))
61        .observe(play_animation_when_ready);
62}
examples/picking/simple_picking.rs (line 27)
12fn setup_scene(
13    mut commands: Commands,
14    mut meshes: ResMut<Assets<Mesh>>,
15    mut materials: ResMut<Assets<StandardMaterial>>,
16) {
17    commands
18        .spawn((
19            Text::new("Click Me to get a box\nDrag cubes to rotate"),
20            Node {
21                position_type: PositionType::Absolute,
22                top: Val::Percent(12.0),
23                left: Val::Percent(12.0),
24                ..default()
25            },
26        ))
27        .observe(on_click_spawn_cube)
28        .observe(
29            |out: Trigger<Pointer<Out>>, mut texts: Query<&mut TextColor>| {
30                let mut text_color = texts.get_mut(out.target()).unwrap();
31                text_color.0 = Color::WHITE;
32            },
33        )
34        .observe(
35            |over: Trigger<Pointer<Over>>, mut texts: Query<&mut TextColor>| {
36                let mut color = texts.get_mut(over.target()).unwrap();
37                color.0 = bevy::color::palettes::tailwind::CYAN_400.into();
38            },
39        );
40
41    // Base
42    commands.spawn((
43        Mesh3d(meshes.add(Circle::new(4.0))),
44        MeshMaterial3d(materials.add(Color::WHITE)),
45        Transform::from_rotation(Quat::from_rotation_x(-std::f32::consts::FRAC_PI_2)),
46    ));
47
48    // Light
49    commands.spawn((
50        PointLight {
51            shadows_enabled: true,
52            ..default()
53        },
54        Transform::from_xyz(4.0, 8.0, 4.0),
55    ));
56
57    // Camera
58    commands.spawn((
59        Camera3d::default(),
60        Transform::from_xyz(-2.5, 4.5, 9.0).looking_at(Vec3::ZERO, Vec3::Y),
61    ));
62}
63
64fn on_click_spawn_cube(
65    _click: Trigger<Pointer<Click>>,
66    mut commands: Commands,
67    mut meshes: ResMut<Assets<Mesh>>,
68    mut materials: ResMut<Assets<StandardMaterial>>,
69    mut num: Local<usize>,
70) {
71    commands
72        .spawn((
73            Mesh3d(meshes.add(Cuboid::new(0.5, 0.5, 0.5))),
74            MeshMaterial3d(materials.add(Color::srgb_u8(124, 144, 255))),
75            Transform::from_xyz(0.0, 0.25 + 0.55 * *num as f32, 0.0),
76        ))
77        // With the MeshPickingPlugin added, you can add pointer event observers to meshes:
78        .observe(on_drag_rotate);
79    *num += 1;
80}
Source

pub fn clone_with( &mut self, target: Entity, config: impl FnOnce(&mut EntityClonerBuilder<'_>) + Send + Sync + 'static, ) -> &mut EntityCommands<'a>

Clones parts of an entity (components, observers, etc.) onto another entity, configured through EntityClonerBuilder.

By default, the other entity will receive all the components of the original that implement Clone or Reflect.

§Panics

The command will panic when applied if the target entity does not exist.

§Example

Configure through EntityClonerBuilder as follows:

#[derive(Component, Clone)]
struct ComponentA(u32);
#[derive(Component, Clone)]
struct ComponentB(u32);

fn example_system(mut commands: Commands) {
    // Create an empty entity.
    let target = commands.spawn_empty().id();

    // Create a new entity and keep its EntityCommands.
    let mut entity = commands.spawn((ComponentA(10), ComponentB(20)));

    // Clone only ComponentA onto the target.
    entity.clone_with(target, |builder| {
        builder.deny::<ComponentB>();
    });
}

See EntityClonerBuilder for more options.

Source

pub fn clone_and_spawn(&mut self) -> EntityCommands<'_>

Spawns a clone of this entity and returns the EntityCommands of the clone.

The clone will receive all the components of the original that implement Clone or Reflect.

To configure cloning behavior (such as only cloning certain components), use EntityCommands::clone_and_spawn_with.

§Note

If the original entity does not exist when this command is applied, the returned entity will have no components.

§Example
#[derive(Component, Clone)]
struct ComponentA(u32);
#[derive(Component, Clone)]
struct ComponentB(u32);

fn example_system(mut commands: Commands) {
    // Create a new entity and store its EntityCommands.
    let mut entity = commands.spawn((ComponentA(10), ComponentB(20)));

    // Create a clone of the first entity.
    let mut entity_clone = entity.clone_and_spawn();
}
Source

pub fn clone_and_spawn_with( &mut self, config: impl FnOnce(&mut EntityClonerBuilder<'_>) + Send + Sync + 'static, ) -> EntityCommands<'_>

Spawns a clone of this entity and allows configuring cloning behavior using EntityClonerBuilder, returning the EntityCommands of the clone.

By default, the clone will receive all the components of the original that implement Clone or Reflect.

To exclude specific components, use EntityClonerBuilder::deny. To only include specific components, use EntityClonerBuilder::deny_all followed by EntityClonerBuilder::allow.

See the methods on EntityClonerBuilder for more options.

§Note

If the original entity does not exist when this command is applied, the returned entity will have no components.

§Example
#[derive(Component, Clone)]
struct ComponentA(u32);
#[derive(Component, Clone)]
struct ComponentB(u32);

fn example_system(mut commands: Commands) {
    // Create a new entity and store its EntityCommands.
    let mut entity = commands.spawn((ComponentA(10), ComponentB(20)));

    // Create a clone of the first entity, but without ComponentB.
    let mut entity_clone = entity.clone_and_spawn_with(|builder| {
        builder.deny::<ComponentB>();
    });
}
Source

pub fn clone_components<B>(&mut self, target: Entity) -> &mut EntityCommands<'a>
where B: Bundle,

Clones the specified components of this entity and inserts them into another entity.

Components can only be cloned if they implement Clone or Reflect.

§Panics

The command will panic when applied if the target entity does not exist.

Source

pub fn move_components<B>(&mut self, target: Entity) -> &mut EntityCommands<'a>
where B: Bundle,

Clones the specified components of this entity and inserts them into another entity, then removes the components from this entity.

Components can only be cloned if they implement Clone or Reflect.

§Panics

The command will panic when applied if the target entity does not exist.

Trait Implementations§

Source§

impl BuildChildrenTransformExt for EntityCommands<'_>

Source§

fn set_parent_in_place(&mut self, parent: Entity) -> &mut EntityCommands<'_>

Change this entity’s parent while preserving this entity’s GlobalTransform by updating its Transform. Read more
Source§

fn remove_parent_in_place(&mut self) -> &mut EntityCommands<'_>

Make this entity parentless while preserving this entity’s GlobalTransform by updating its Transform to be equal to its current GlobalTransform. Read more
Source§

impl ReflectCommandExt for EntityCommands<'_>

Source§

fn insert_reflect( &mut self, component: Box<dyn PartialReflect>, ) -> &mut EntityCommands<'_>

Adds the given boxed reflect component or bundle to the entity using the reflection data in AppTypeRegistry. Read more
Source§

fn insert_reflect_with_registry<T>( &mut self, component: Box<dyn PartialReflect>, ) -> &mut EntityCommands<'_>

Same as insert_reflect, but using the T resource as type registry instead of AppTypeRegistry. Read more
Source§

fn remove_reflect( &mut self, component_type_path: impl Into<Cow<'static, str>>, ) -> &mut EntityCommands<'_>

Removes from the entity the component or bundle with the given type name registered in AppTypeRegistry. Read more
Source§

fn remove_reflect_with_registry<T>( &mut self, component_type_path: impl Into<Cow<'static, str>>, ) -> &mut EntityCommands<'_>

Same as remove_reflect, but using the T resource as type registry instead of AppTypeRegistry.

Auto Trait Implementations§

§

impl<'a> Freeze for EntityCommands<'a>

§

impl<'a> RefUnwindSafe for EntityCommands<'a>

§

impl<'a> Send for EntityCommands<'a>

§

impl<'a> Sync for EntityCommands<'a>

§

impl<'a> Unpin for EntityCommands<'a>

§

impl<'a> !UnwindSafe for EntityCommands<'a>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T, U> AsBindGroupShaderType<U> for T
where U: ShaderType, &'a T: for<'a> Into<U>,

Source§

fn as_bind_group_shader_type(&self, _images: &RenderAssets<GpuImage>) -> U

Return the T ShaderType for self. When used in AsBindGroup derives, it is safe to assume that all images in self exist.
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> Conv for T

Source§

fn conv<T>(self) -> T
where Self: Into<T>,

Converts self into T using Into<T>. Read more
Source§

impl<T> Downcast<T> for T

Source§

fn downcast(&self) -> &T

Source§

impl<T> Downcast for T
where T: Any,

Source§

fn into_any(self: Box<T>) -> Box<dyn Any>

Converts 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>

Converts 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)

Converts &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)

Converts &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 T
where T: Any,

Source§

fn into_any(self: Box<T>) -> Box<dyn Any>

Convert 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>

Convert 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)

Convert &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)

Convert &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
where T: Any + Send,

Source§

fn into_any_send(self: Box<T>) -> Box<dyn Any + Send>

Converts Box<Trait> (where Trait: DowncastSend) to Box<dyn Any + Send>, which can then be downcast into Box<ConcreteType> where ConcreteType implements Trait.
Source§

impl<T> DowncastSync for T
where T: Any + Send + Sync,

Source§

fn into_any_arc(self: Arc<T>) -> Arc<dyn Any + Sync + Send>

Convert Arc<Trait> (where Trait: Downcast) to Arc<Any>. Arc<Any> can then be further downcast into Arc<ConcreteType> where ConcreteType implements Trait.
Source§

impl<T> FmtForward for T

Source§

fn fmt_binary(self) -> FmtBinary<Self>
where Self: Binary,

Causes self to use its Binary implementation when Debug-formatted.
Source§

fn fmt_display(self) -> FmtDisplay<Self>
where Self: Display,

Causes self to use its Display implementation when Debug-formatted.
Source§

fn fmt_lower_exp(self) -> FmtLowerExp<Self>
where Self: LowerExp,

Causes self to use its LowerExp implementation when Debug-formatted.
Source§

fn fmt_lower_hex(self) -> FmtLowerHex<Self>
where Self: LowerHex,

Causes self to use its LowerHex implementation when Debug-formatted.
Source§

fn fmt_octal(self) -> FmtOctal<Self>
where Self: Octal,

Causes self to use its Octal implementation when Debug-formatted.
Source§

fn fmt_pointer(self) -> FmtPointer<Self>
where Self: Pointer,

Causes self to use its Pointer implementation when Debug-formatted.
Source§

fn fmt_upper_exp(self) -> FmtUpperExp<Self>
where Self: UpperExp,

Causes self to use its UpperExp implementation when Debug-formatted.
Source§

fn fmt_upper_hex(self) -> FmtUpperHex<Self>
where Self: UpperHex,

Causes self to use its UpperHex implementation when Debug-formatted.
Source§

fn fmt_list(self) -> FmtList<Self>
where &'a Self: for<'a> IntoIterator,

Formats each item in a sequence. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<S> FromSample<S> for S

Source§

fn from_sample_(s: S) -> S

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts 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 more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts 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 more
Source§

impl<F, T> IntoSample<T> for F
where T: FromSample<F>,

Source§

fn into_sample(self) -> T

Source§

impl<T> Pipe for T
where T: ?Sized,

Source§

fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> R
where Self: Sized,

Pipes by value. This is generally the method you want to use. Read more
Source§

fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> R
where R: 'a,

Borrows self and passes that borrow into the pipe function. Read more
Source§

fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> R
where R: 'a,

Mutably borrows self and passes that borrow into the pipe function. Read more
Source§

fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
where Self: Borrow<B>, B: 'a + ?Sized, R: 'a,

Borrows self, then passes self.borrow() into the pipe function. Read more
Source§

fn pipe_borrow_mut<'a, B, R>( &'a mut self, func: impl FnOnce(&'a mut B) -> R, ) -> R
where Self: BorrowMut<B>, B: 'a + ?Sized, R: 'a,

Mutably borrows self, then passes self.borrow_mut() into the pipe function. Read more
Source§

fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
where Self: AsRef<U>, U: 'a + ?Sized, R: 'a,

Borrows 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
where Self: AsMut<U>, U: 'a + ?Sized, R: 'a,

Mutably borrows 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
where Self: Deref<Target = T>, T: 'a + ?Sized, R: 'a,

Borrows self, then passes self.deref() into the pipe function.
Source§

fn pipe_deref_mut<'a, T, R>( &'a mut self, func: impl FnOnce(&'a mut T) -> R, ) -> R
where Self: DerefMut<Target = T> + Deref, T: 'a + ?Sized, R: 'a,

Mutably borrows self, then passes self.deref_mut() into the pipe function.
Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T> Tap for T

Source§

fn tap(self, func: impl FnOnce(&Self)) -> Self

Immutable access to a value. Read more
Source§

fn tap_mut(self, func: impl FnOnce(&mut Self)) -> Self

Mutable access to a value. Read more
Source§

fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
where Self: Borrow<B>, B: ?Sized,

Immutable access to the Borrow<B> of a value. Read more
Source§

fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
where Self: BorrowMut<B>, B: ?Sized,

Mutable access to the BorrowMut<B> of a value. Read more
Source§

fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
where Self: AsRef<R>, R: ?Sized,

Immutable access to the AsRef<R> view of a value. Read more
Source§

fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
where Self: AsMut<R>, R: ?Sized,

Mutable access to the AsMut<R> view of a value. Read more
Source§

fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
where Self: Deref<Target = T>, T: ?Sized,

Immutable access to the Deref::Target of a value. Read more
Source§

fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
where Self: DerefMut<Target = T> + Deref, T: ?Sized,

Mutable access to the Deref::Target of a value. Read more
Source§

fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self

Calls .tap() only in debug builds, and is erased in release builds.
Source§

fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self

Calls .tap_mut() only in debug builds, and is erased in release builds.
Source§

fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
where Self: Borrow<B>, B: ?Sized,

Calls .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
where Self: BorrowMut<B>, B: ?Sized,

Calls .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
where Self: AsRef<R>, R: ?Sized,

Calls .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
where Self: AsMut<R>, R: ?Sized,

Calls .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
where Self: Deref<Target = T>, T: ?Sized,

Calls .tap_deref() only in debug builds, and is erased in release builds.
Source§

fn tap_deref_mut_dbg<T>(self, func: impl FnOnce(&mut T)) -> Self
where Self: DerefMut<Target = T> + Deref, T: ?Sized,

Calls .tap_deref_mut() only in debug builds, and is erased in release builds.
Source§

impl<T, U> ToSample<U> for T
where U: FromSample<T>,

Source§

fn to_sample_(self) -> U

Source§

impl<T> TryConv for T

Source§

fn try_conv<T>(self) -> Result<T, Self::Error>
where Self: TryInto<T>,

Attempts to convert self into T using TryInto<T>. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> Upcast<T> for T

Source§

fn upcast(&self) -> Option<&T>

Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

impl<T> ConditionalSend for T
where T: Send,

Source§

impl<S, T> Duplex<S> for T
where T: FromSample<S> + ToSample<S>,

Source§

impl<T> Settings for T
where T: 'static + Send + Sync,

Source§

impl<T> WasmNotSend for T
where T: Send,

Source§

impl<T> WasmNotSendSync for T

Source§

impl<T> WasmNotSync for T
where T: Sync,