EntityCommands

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 via the DefaultErrorHandler resource.

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/app/log_layers_ecs.rs (lines 151-164)
144fn print_logs(
145    mut log_message_reader: MessageReader<LogMessage>,
146    mut commands: Commands,
147    log_viewer_root: Single<Entity, With<LogViewerRoot>>,
148) {
149    let root_entity = *log_viewer_root;
150
151    commands.entity(root_entity).with_children(|child| {
152        for log_message in log_message_reader.read() {
153            child.spawn((
154                Text::default(),
155                children![
156                    (
157                        TextSpan::new(format!("{:5} ", log_message.level)),
158                        TextColor(level_color(&log_message.level)),
159                    ),
160                    TextSpan::new(&log_message.message),
161                ],
162            ));
163        }
164    });
165}
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}
examples/stress_tests/many_glyphs.rs (lines 86-93)
64fn setup(mut commands: Commands, args: Res<Args>) {
65    warn!(include_str!("warning_string.txt"));
66
67    commands.spawn(Camera2d);
68    let text_string = "0123456789".repeat(10_000);
69    let text_font = TextFont {
70        font_size: 4.,
71        ..Default::default()
72    };
73    let text_block = TextLayout {
74        justify: Justify::Left,
75        linebreak: LineBreak::AnyCharacter,
76    };
77
78    if !args.no_ui {
79        commands
80            .spawn(Node {
81                width: percent(100),
82                align_items: AlignItems::Center,
83                justify_content: JustifyContent::Center,
84                ..default()
85            })
86            .with_children(|commands| {
87                commands
88                    .spawn(Node {
89                        width: px(1000),
90                        ..Default::default()
91                    })
92                    .with_child((Text(text_string.clone()), text_font.clone(), text_block));
93            });
94    }
95
96    if !args.no_text2d {
97        commands.spawn((
98            Text2d::new(text_string),
99            text_font.clone(),
100            TextColor(RED.into()),
101            bevy::sprite::Anchor::CENTER,
102            TextBounds::new_horizontal(1000.),
103            text_block,
104        ));
105    }
106}
examples/stress_tests/text_pipeline.rs (lines 73-77)
34fn spawn(mut commands: Commands, asset_server: Res<AssetServer>) {
35    warn!(include_str!("warning_string.txt"));
36
37    commands.spawn(Camera2d);
38
39    let make_spans = |i| {
40        [
41            (
42                TextSpan("text".repeat(i)),
43                TextFont {
44                    font: asset_server.load("fonts/FiraMono-Medium.ttf"),
45                    font_size: (4 + i % 10) as f32,
46                    ..Default::default()
47                },
48                TextColor(BLUE.into()),
49            ),
50            (
51                TextSpan("pipeline".repeat(i)),
52                TextFont {
53                    font: asset_server.load("fonts/FiraSans-Bold.ttf"),
54                    font_size: (4 + i % 11) as f32,
55                    ..default()
56                },
57                TextColor(YELLOW.into()),
58            ),
59        ]
60    };
61
62    let spans = (1..50).flat_map(|i| make_spans(i).into_iter());
63
64    commands
65        .spawn((
66            Text2d::default(),
67            TextLayout {
68                justify: Justify::Center,
69                linebreak: LineBreak::AnyCharacter,
70            },
71            TextBounds::default(),
72        ))
73        .with_children(|p| {
74            for span in spans {
75                p.spawn(span);
76            }
77        });
78}
examples/ui/text_background_colors.rs (lines 41-63)
24fn setup(mut commands: Commands) {
25    // UI camera
26    commands.spawn(Camera2d);
27
28    let message_text = [
29        "T", "e", "x", "t\n", "B", "a", "c", "k", "g", "r", "o", "u", "n", "d\n", "C", "o", "l",
30        "o", "r", "s", "!",
31    ];
32
33    commands
34        .spawn(Node {
35            width: percent(100),
36            height: percent(100),
37            justify_content: JustifyContent::Center,
38            align_items: AlignItems::Center,
39            ..Default::default()
40        })
41        .with_children(|commands| {
42            commands
43                .spawn((
44                    Text::default(),
45                    TextLayout {
46                        justify: Justify::Center,
47                        ..Default::default()
48                    },
49                ))
50                .with_children(|commands| {
51                    for (i, section_str) in message_text.iter().enumerate() {
52                        commands.spawn((
53                            TextSpan::new(*section_str),
54                            TextColor::BLACK,
55                            TextFont {
56                                font_size: 100.,
57                                ..default()
58                            },
59                            TextBackgroundColor(PALETTE[i % PALETTE.len()]),
60                        ));
61                    }
62                });
63        });
64}
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: percent(100),
118            height: percent(100),
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: px(300),
130                justify_content: JustifyContent::Center,
131                align_items: AlignItems::Center,
132                margin: UiRect::all(px(12)),
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: percent(100),
144            height: 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: px(200),
168                        height: px(120),
169                        // Add a border so we can show which element is focused
170                        border: UiRect::all(px(4)),
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(px(16)),
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: Justify::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 160)
37fn setup(
38    mut commands: Commands,
39    asset_server: Res<AssetServer>,
40    mut meshes: ResMut<Assets<Mesh>>,
41    mut materials: ResMut<Assets<StandardMaterial>>,
42    mut skinned_mesh_inverse_bindposes_assets: ResMut<Assets<SkinnedMeshInverseBindposes>>,
43) {
44    // Create a camera
45    commands.spawn((
46        Camera3d::default(),
47        Transform::from_xyz(2.5, 2.5, 9.0).looking_at(Vec3::ZERO, Vec3::Y),
48    ));
49
50    // Create inverse bindpose matrices for a skeleton consists of 2 joints
51    let inverse_bindposes = skinned_mesh_inverse_bindposes_assets.add(vec![
52        Mat4::from_translation(Vec3::new(-0.5, -1.0, 0.0)),
53        Mat4::from_translation(Vec3::new(-0.5, -1.0, 0.0)),
54    ]);
55
56    // Create a mesh
57    let mesh = Mesh::new(
58        PrimitiveTopology::TriangleList,
59        RenderAssetUsages::RENDER_WORLD,
60    )
61    // Set mesh vertex positions
62    .with_inserted_attribute(
63        Mesh::ATTRIBUTE_POSITION,
64        vec![
65            [0.0, 0.0, 0.0],
66            [1.0, 0.0, 0.0],
67            [0.0, 0.5, 0.0],
68            [1.0, 0.5, 0.0],
69            [0.0, 1.0, 0.0],
70            [1.0, 1.0, 0.0],
71            [0.0, 1.5, 0.0],
72            [1.0, 1.5, 0.0],
73            [0.0, 2.0, 0.0],
74            [1.0, 2.0, 0.0],
75        ],
76    )
77    // Add UV coordinates that map the left half of the texture since its a 1 x
78    // 2 rectangle.
79    .with_inserted_attribute(
80        Mesh::ATTRIBUTE_UV_0,
81        vec![
82            [0.0, 0.00],
83            [0.5, 0.00],
84            [0.0, 0.25],
85            [0.5, 0.25],
86            [0.0, 0.50],
87            [0.5, 0.50],
88            [0.0, 0.75],
89            [0.5, 0.75],
90            [0.0, 1.00],
91            [0.5, 1.00],
92        ],
93    )
94    // Set mesh vertex normals
95    .with_inserted_attribute(Mesh::ATTRIBUTE_NORMAL, vec![[0.0, 0.0, 1.0]; 10])
96    // Set mesh vertex joint indices for mesh skinning.
97    // Each vertex gets 4 indices used to address the `JointTransforms` array in the vertex shader
98    //  as well as `SkinnedMeshJoint` array in the `SkinnedMesh` component.
99    // This means that a maximum of 4 joints can affect a single vertex.
100    .with_inserted_attribute(
101        Mesh::ATTRIBUTE_JOINT_INDEX,
102        // Need to be explicit here as [u16; 4] could be either Uint16x4 or Unorm16x4.
103        VertexAttributeValues::Uint16x4(vec![
104            [0, 0, 0, 0],
105            [0, 0, 0, 0],
106            [0, 1, 0, 0],
107            [0, 1, 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        ]),
115    )
116    // Set mesh vertex joint weights for mesh skinning.
117    // Each vertex gets 4 joint weights corresponding to the 4 joint indices assigned to it.
118    // The sum of these weights should equal to 1.
119    .with_inserted_attribute(
120        Mesh::ATTRIBUTE_JOINT_WEIGHT,
121        vec![
122            [1.00, 0.00, 0.0, 0.0],
123            [1.00, 0.00, 0.0, 0.0],
124            [0.75, 0.25, 0.0, 0.0],
125            [0.75, 0.25, 0.0, 0.0],
126            [0.50, 0.50, 0.0, 0.0],
127            [0.50, 0.50, 0.0, 0.0],
128            [0.25, 0.75, 0.0, 0.0],
129            [0.25, 0.75, 0.0, 0.0],
130            [0.00, 1.00, 0.0, 0.0],
131            [0.00, 1.00, 0.0, 0.0],
132        ],
133    )
134    // Tell bevy to construct triangles from a list of vertex indices,
135    // where each 3 vertex indices form a triangle.
136    .with_inserted_indices(Indices::U16(vec![
137        0, 1, 3, 0, 3, 2, 2, 3, 5, 2, 5, 4, 4, 5, 7, 4, 7, 6, 6, 7, 9, 6, 9, 8,
138    ]));
139
140    let mesh = meshes.add(mesh);
141
142    // We're seeding the PRNG here to make this example deterministic for testing purposes.
143    // This isn't strictly required in practical use unless you need your app to be deterministic.
144    let mut rng = ChaCha8Rng::seed_from_u64(42);
145
146    for i in -5..5 {
147        // Create joint entities
148        let joint_0 = commands
149            .spawn(Transform::from_xyz(
150                i as f32 * 1.5,
151                0.0,
152                // Move quads back a small amount to avoid Z-fighting and not
153                // obscure the transform gizmos.
154                -(i as f32 * 0.01).abs(),
155            ))
156            .id();
157        let joint_1 = commands.spawn((AnimatedJoint(i), Transform::IDENTITY)).id();
158
159        // Set joint_1 as a child of joint_0.
160        commands.entity(joint_0).add_children(&[joint_1]);
161
162        // Each joint in this vector corresponds to each inverse bindpose matrix in `SkinnedMeshInverseBindposes`.
163        let joint_entities = vec![joint_0, joint_1];
164
165        // Create skinned mesh renderer. Note that its transform doesn't affect the position of the mesh.
166        commands.spawn((
167            Mesh3d(mesh.clone()),
168            MeshMaterial3d(materials.add(StandardMaterial {
169                base_color: Color::srgb(
170                    rng.random_range(0.0..1.0),
171                    rng.random_range(0.0..1.0),
172                    rng.random_range(0.0..1.0),
173                ),
174                base_color_texture: Some(asset_server.load("textures/uv_checker_bw.png")),
175                ..default()
176            })),
177            SkinnedMesh {
178                inverse_bindposes: inverse_bindposes.clone(),
179                joints: joint_entities,
180            },
181        ));
182    }
183}
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: percent(100),
41            height: 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(px(15), 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 `Justify` 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(Justify::Right),
76            Node {
77                max_width: 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: 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(px(15), 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(Justify::Center),
118                Node {
119                    max_width: 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(Justify::Left),
134                Node {
135                    max_width: 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(Justify::Justified),
149                TextColor(GREEN_YELLOW.into()),
150                Node {
151                    max_width: 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}
Source

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

Removes all the children from this entity. See also clear_related

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 insert_child( &mut self, index: usize, child: 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 328)
281fn spawn_small_cubes(
282    commands: &mut Commands,
283    meshes: &mut Assets<Mesh>,
284    materials: &mut Assets<StandardMaterial>,
285) {
286    // Add the cube mesh.
287    let small_cube = meshes.add(Cuboid::new(
288        SMALL_CUBE_SIZE,
289        SMALL_CUBE_SIZE,
290        SMALL_CUBE_SIZE,
291    ));
292
293    // Add the cube material.
294    let small_cube_material = materials.add(StandardMaterial {
295        base_color: SILVER.into(),
296        ..default()
297    });
298
299    // Create the entity that the small cubes will be parented to. This is the
300    // entity that we rotate.
301    let sphere_parent = commands
302        .spawn(Transform::from_translation(Vec3::ZERO))
303        .insert(Visibility::default())
304        .insert(SphereParent)
305        .id();
306
307    // Now we have to figure out where to place the cubes. To do that, we create
308    // a sphere mesh, but we don't add it to the scene. Instead, we inspect the
309    // sphere mesh to find the positions of its vertices, and spawn a small cube
310    // at each one. That way, we end up with a bunch of cubes arranged in a
311    // spherical shape.
312
313    // Create the sphere mesh, and extract the positions of its vertices.
314    let sphere = Sphere::new(OUTER_RADIUS)
315        .mesh()
316        .ico(OUTER_SUBDIVISION_COUNT)
317        .unwrap();
318    let sphere_positions = sphere.attribute(Mesh::ATTRIBUTE_POSITION).unwrap();
319
320    // At each vertex, create a small cube.
321    for sphere_position in sphere_positions.as_float3().unwrap() {
322        let sphere_position = Vec3::from_slice(sphere_position);
323        let small_cube = commands
324            .spawn(Mesh3d(small_cube.clone()))
325            .insert(MeshMaterial3d(small_cube_material.clone()))
326            .insert(Transform::from_translation(sphere_position))
327            .id();
328        commands.entity(sphere_parent).add_child(small_cube);
329    }
330}
examples/animation/animation_graph.rs (line 335)
271fn setup_node_rects(commands: &mut Commands) {
272    for (node_rect, node_type) in NODE_RECTS.iter().zip(NODE_TYPES.iter()) {
273        let node_string = match *node_type {
274            NodeType::Clip(ref clip) => clip.text,
275            NodeType::Blend(text) => text,
276        };
277
278        let text = commands
279            .spawn((
280                Text::new(node_string),
281                TextFont {
282                    font_size: 16.0,
283                    ..default()
284                },
285                TextColor(ANTIQUE_WHITE.into()),
286                TextLayout::new_with_justify(Justify::Center),
287            ))
288            .id();
289
290        let container = {
291            let mut container = commands.spawn((
292                Node {
293                    position_type: PositionType::Absolute,
294                    bottom: px(node_rect.bottom),
295                    left: px(node_rect.left),
296                    height: px(node_rect.height),
297                    width: px(node_rect.width),
298                    align_items: AlignItems::Center,
299                    justify_items: JustifyItems::Center,
300                    align_content: AlignContent::Center,
301                    justify_content: JustifyContent::Center,
302                    ..default()
303                },
304                BorderColor::all(WHITE),
305                Outline::new(px(1), Val::ZERO, Color::WHITE),
306            ));
307
308            if let NodeType::Clip(clip) = node_type {
309                container.insert((
310                    Interaction::None,
311                    RelativeCursorPosition::default(),
312                    (*clip).clone(),
313                ));
314            }
315
316            container.id()
317        };
318
319        // Create the background color.
320        if let NodeType::Clip(_) = node_type {
321            let background = commands
322                .spawn((
323                    Node {
324                        position_type: PositionType::Absolute,
325                        top: px(0),
326                        left: px(0),
327                        height: px(node_rect.height),
328                        width: px(node_rect.width),
329                        ..default()
330                    },
331                    BackgroundColor(DARK_GREEN.into()),
332                ))
333                .id();
334
335            commands.entity(container).add_child(background);
336        }
337
338        commands.entity(container).add_child(text);
339    }
340}
examples/3d/irradiance_volumes.rs (line 589)
525fn create_cubes(
526    image_assets: Res<Assets<Image>>,
527    mut commands: Commands,
528    irradiance_volumes: Query<(&IrradianceVolume, &GlobalTransform)>,
529    voxel_cube_parents: Query<Entity, With<VoxelCubeParent>>,
530    voxel_cubes: Query<Entity, With<VoxelCube>>,
531    example_assets: Res<ExampleAssets>,
532    mut voxel_visualization_material_assets: ResMut<Assets<VoxelVisualizationMaterial>>,
533) {
534    // If voxel cubes have already been spawned, don't do anything.
535    if !voxel_cubes.is_empty() {
536        return;
537    }
538
539    let Some(voxel_cube_parent) = voxel_cube_parents.iter().next() else {
540        return;
541    };
542
543    for (irradiance_volume, global_transform) in irradiance_volumes.iter() {
544        let Some(image) = image_assets.get(&irradiance_volume.voxels) else {
545            continue;
546        };
547
548        let resolution = image.texture_descriptor.size;
549
550        let voxel_cube_material = voxel_visualization_material_assets.add(ExtendedMaterial {
551            base: StandardMaterial::from(Color::from(RED)),
552            extension: VoxelVisualizationExtension {
553                irradiance_volume_info: VoxelVisualizationIrradianceVolumeInfo {
554                    world_from_voxel: VOXEL_FROM_WORLD.inverse(),
555                    voxel_from_world: VOXEL_FROM_WORLD,
556                    resolution: uvec3(
557                        resolution.width,
558                        resolution.height,
559                        resolution.depth_or_array_layers,
560                    ),
561                    intensity: IRRADIANCE_VOLUME_INTENSITY,
562                },
563            },
564        });
565
566        let scale = vec3(
567            1.0 / resolution.width as f32,
568            1.0 / resolution.height as f32,
569            1.0 / resolution.depth_or_array_layers as f32,
570        );
571
572        // Spawn a cube for each voxel.
573        for z in 0..resolution.depth_or_array_layers {
574            for y in 0..resolution.height {
575                for x in 0..resolution.width {
576                    let uvw = (uvec3(x, y, z).as_vec3() + 0.5) * scale - 0.5;
577                    let pos = global_transform.transform_point(uvw);
578                    let voxel_cube = commands
579                        .spawn((
580                            Mesh3d(example_assets.voxel_cube.clone()),
581                            MeshMaterial3d(voxel_cube_material.clone()),
582                            Transform::from_scale(Vec3::splat(VOXEL_CUBE_SCALE))
583                                .with_translation(pos),
584                        ))
585                        .insert(VoxelCube)
586                        .insert(NotShadowCaster)
587                        .id();
588
589                    commands.entity(voxel_cube_parent).add_child(voxel_cube);
590                }
591            }
592        }
593    }
594}
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::rng();
383    // used to count through the number of children (used only for visual layout)
384    let mut child_idx: Vec<u16> = vec![0; count];
385
386    // insert children
387    for (current_idx, &parent_idx) in parent_map.iter().enumerate() {
388        let current_idx = current_idx + 1;
389
390        // separation factor to visually separate children (0..1)
391        let sep = child_idx[parent_idx] as f32 / node_info[parent_idx].child_count as f32;
392        child_idx[parent_idx] += 1;
393
394        // calculate and set depth
395        // this works because it's guaranteed that we have already iterated over the parent
396        let depth = node_info[parent_idx].depth + 1;
397        let info = &mut node_info[current_idx];
398        info.depth = depth;
399
400        // update max depth of tree
401        result.maximum_depth = result.maximum_depth.max(depth.try_into().unwrap());
402
403        // insert child
404        let child_entity = {
405            let mut cmd = commands.spawn_empty();
406
407            // check whether or not to update this node
408            let update = (rng.random::<f32>() <= update_filter.probability)
409                && (depth >= update_filter.min_depth && depth <= update_filter.max_depth);
410
411            if update {
412                cmd.insert(UpdateValue(sep));
413                result.active_nodes += 1;
414            }
415
416            let transform = {
417                let mut translation = Vec3::ZERO;
418                // use the same placement fn as the `update` system
419                // this way the entities won't be all at (0, 0, 0) when they don't have an `Update` component
420                set_translation(&mut translation, sep);
421                Transform::from_translation(translation)
422            };
423
424            // only insert the components necessary for the transform propagation
425            cmd.insert(transform);
426
427            cmd.id()
428        };
429
430        commands.entity(ents[parent_idx]).add_child(child_entity);
431
432        ents.push(child_entity);
433    }
434
435    result.inserted_nodes = ents.len();
436    result
437}
examples/ui/text_wrap_debug.rs (line 123)
44fn spawn(mut commands: Commands, asset_server: Res<AssetServer>) {
45    commands.spawn(Camera2d);
46
47    let text_font = TextFont {
48        font: asset_server.load("fonts/FiraSans-Bold.ttf"),
49        font_size: 12.0,
50        ..default()
51    };
52
53    let root = commands
54        .spawn((
55            Node {
56                width: percent(100),
57                height: percent(100),
58                flex_direction: FlexDirection::Column,
59                ..default()
60            },
61            BackgroundColor(Color::BLACK),
62        ))
63        .id();
64
65    for linebreak in [
66        LineBreak::AnyCharacter,
67        LineBreak::WordBoundary,
68        LineBreak::WordOrCharacter,
69        LineBreak::NoWrap,
70    ] {
71        let row_id = commands
72            .spawn(Node {
73                flex_direction: FlexDirection::Row,
74                justify_content: JustifyContent::SpaceAround,
75                align_items: AlignItems::Center,
76                width: percent(100),
77                height: percent(50),
78                ..default()
79            })
80            .id();
81
82        let justifications = vec![
83            JustifyContent::Center,
84            JustifyContent::FlexStart,
85            JustifyContent::FlexEnd,
86            JustifyContent::SpaceAround,
87            JustifyContent::SpaceBetween,
88            JustifyContent::SpaceEvenly,
89        ];
90
91        for (i, justification) in justifications.into_iter().enumerate() {
92            let c = 0.3 + i as f32 * 0.1;
93            let column_id = commands
94                .spawn((
95                    Node {
96                        justify_content: justification,
97                        flex_direction: FlexDirection::Column,
98                        width: percent(16),
99                        height: percent(95),
100                        overflow: Overflow::clip_x(),
101                        ..default()
102                    },
103                    BackgroundColor(Color::srgb(0.5, c, 1.0 - c)),
104                ))
105                .id();
106
107            let messages = [
108                format!("JustifyContent::{justification:?}"),
109                format!("LineBreakOn::{linebreak:?}"),
110                "Line 1\nLine 2".to_string(),
111                "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas auctor, nunc ac faucibus fringilla.".to_string(),
112                "pneumonoultramicroscopicsilicovolcanoconiosis".to_string()
113            ];
114
115            for (j, message) in messages.into_iter().enumerate() {
116                commands.entity(column_id).with_child((
117                    Text(message.clone()),
118                    text_font.clone(),
119                    TextLayout::new(Justify::Left, linebreak),
120                    BackgroundColor(Color::srgb(0.8 - j as f32 * 0.2, 0., 0.)),
121                ));
122            }
123            commands.entity(row_id).add_child(column_id);
124        }
125        commands.entity(root).add_child(row_id);
126    }
127}
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 remove_child(&mut self, child: Entity) -> &mut EntityCommands<'a>

Removes the relationship between this entity and the given entity.

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 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/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: 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}
More examples
Hide additional examples
examples/camera/first_person_view_model.rs (lines 198-202)
190fn spawn_text(mut commands: Commands) {
191    commands
192        .spawn(Node {
193            position_type: PositionType::Absolute,
194            bottom: px(12),
195            left: px(12),
196            ..default()
197        })
198        .with_child(Text::new(concat!(
199            "Move the camera with your mouse.\n",
200            "Press arrow up to decrease the FOV of the world model.\n",
201            "Press arrow down to increase the FOV of the world model."
202        )));
203}
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: px(12),
155                left: 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: percent(100),
251                width: percent(100),
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/stress_tests/many_glyphs.rs (line 92)
64fn setup(mut commands: Commands, args: Res<Args>) {
65    warn!(include_str!("warning_string.txt"));
66
67    commands.spawn(Camera2d);
68    let text_string = "0123456789".repeat(10_000);
69    let text_font = TextFont {
70        font_size: 4.,
71        ..Default::default()
72    };
73    let text_block = TextLayout {
74        justify: Justify::Left,
75        linebreak: LineBreak::AnyCharacter,
76    };
77
78    if !args.no_ui {
79        commands
80            .spawn(Node {
81                width: percent(100),
82                align_items: AlignItems::Center,
83                justify_content: JustifyContent::Center,
84                ..default()
85            })
86            .with_children(|commands| {
87                commands
88                    .spawn(Node {
89                        width: px(1000),
90                        ..Default::default()
91                    })
92                    .with_child((Text(text_string.clone()), text_font.clone(), text_block));
93            });
94    }
95
96    if !args.no_text2d {
97        commands.spawn((
98            Text2d::new(text_string),
99            text_font.clone(),
100            TextColor(RED.into()),
101            bevy::sprite::Anchor::CENTER,
102            TextBounds::new_horizontal(1000.),
103            text_block,
104        ));
105    }
106}
examples/testbed/ui.rs (lines 483-487)
454    pub fn setup(mut commands: Commands) {
455        commands.spawn((Camera2d, DespawnOnExit(super::Scene::TextWrap)));
456
457        let root = commands
458            .spawn((
459                Node {
460                    flex_direction: FlexDirection::Column,
461                    width: px(200),
462                    height: percent(100),
463                    overflow: Overflow::clip_x(),
464                    ..default()
465                },
466                BackgroundColor(Color::BLACK),
467                DespawnOnExit(super::Scene::TextWrap),
468            ))
469            .id();
470
471        for linebreak in [
472            LineBreak::AnyCharacter,
473            LineBreak::WordBoundary,
474            LineBreak::WordOrCharacter,
475            LineBreak::NoWrap,
476        ] {
477            let messages = [
478                "Lorem ipsum dolor sit amet, consectetur adipiscing elit.".to_string(),
479                "pneumonoultramicroscopicsilicovolcanoconiosis".to_string(),
480            ];
481
482            for (j, message) in messages.into_iter().enumerate() {
483                commands.entity(root).with_child((
484                    Text(message.clone()),
485                    TextLayout::new(Justify::Left, linebreak),
486                    BackgroundColor(Color::srgb(0.8 - j as f32 * 0.3, 0., 0.)),
487                ));
488            }
489        }
490    }
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_related_entities` 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_related_entities` 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_related_entities` 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_related_entities` 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.

Removes the relation R between this entity and all its related entities.

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.

Examples found in repository?
examples/diagnostics/log_diagnostics.rs (line 197)
180fn update_commands(
181    mut commands: Commands,
182    log_commands: Single<Entity, With<LogDiagnosticsCommands>>,
183    status: Res<LogDiagnosticsStatus>,
184    filters: Res<LogDiagnosticsFilters>,
185) {
186    let enabled = *status == LogDiagnosticsStatus::Enabled;
187    let alpha = if enabled { 1. } else { 0.25 };
188    let enabled_color = |enabled| {
189        if enabled {
190            Color::from(palettes::tailwind::GREEN_400)
191        } else {
192            Color::from(palettes::tailwind::RED_400)
193        }
194    };
195    commands
196        .entity(*log_commands)
197        .despawn_related::<Children>()
198        .insert(children![
199            (
200                Node {
201                    flex_direction: FlexDirection::Row,
202                    column_gap: px(5),
203                    ..default()
204                },
205                children![
206                    Text::new("[Q] Toggle filtering:"),
207                    (
208                        Text::new(format!("{:?}", *status)),
209                        TextColor(enabled_color(enabled))
210                    )
211                ]
212            ),
213            (
214                Node {
215                    flex_direction: FlexDirection::Row,
216                    column_gap: px(5),
217                    ..default()
218                },
219                children![
220                    (
221                        Text::new("[1] Frame times:"),
222                        TextColor(Color::WHITE.with_alpha(alpha))
223                    ),
224                    (
225                        Text::new(format!("{:?}", filters.frame_time)),
226                        TextColor(enabled_color(filters.frame_time).with_alpha(alpha))
227                    )
228                ]
229            ),
230            (
231                Node {
232                    flex_direction: FlexDirection::Row,
233                    column_gap: px(5),
234                    ..default()
235                },
236                children![
237                    (
238                        Text::new("[2] Entity count:"),
239                        TextColor(Color::WHITE.with_alpha(alpha))
240                    ),
241                    (
242                        Text::new(format!("{:?}", filters.entity_count)),
243                        TextColor(enabled_color(filters.entity_count).with_alpha(alpha))
244                    )
245                ]
246            ),
247            (
248                Node {
249                    flex_direction: FlexDirection::Row,
250                    column_gap: px(5),
251                    ..default()
252                },
253                children![
254                    (
255                        Text::new("[3] System info:"),
256                        TextColor(Color::WHITE.with_alpha(alpha))
257                    ),
258                    (
259                        Text::new(format!("{:?}", filters.system_info)),
260                        TextColor(enabled_color(filters.system_info).with_alpha(alpha))
261                    )
262                ]
263            ),
264            (
265                Node {
266                    flex_direction: FlexDirection::Row,
267                    column_gap: px(5),
268                    ..default()
269                },
270                children![
271                    (
272                        Text::new("[4] Render diagnostics:"),
273                        TextColor(Color::WHITE.with_alpha(alpha))
274                    ),
275                    (
276                        Text::new("Private"),
277                        TextColor(enabled_color(false).with_alpha(alpha))
278                    )
279                ]
280            ),
281        ]);
282}
Source

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

Despawns the children of this entity. This entity will not be despawned.

This is a specialization of despawn_related, a more general method for despawning via relationships.

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/ui/scrollbars.rs (line 31)
30fn setup_view_root(mut commands: Commands) {
31    let camera = commands.spawn((Camera::default(), Camera2d)).id();
32
33    commands.spawn((
34        Node {
35            display: Display::Flex,
36            flex_direction: FlexDirection::Column,
37            position_type: PositionType::Absolute,
38            left: px(0),
39            top: px(0),
40            right: px(0),
41            bottom: px(0),
42            padding: UiRect::all(px(3)),
43            row_gap: px(6),
44            ..Default::default()
45        },
46        BackgroundColor(Color::srgb(0.1, 0.1, 0.1)),
47        UiTargetCamera(camera),
48        TabGroup::default(),
49        Children::spawn((Spawn(Text::new("Scrolling")), Spawn(scroll_area_demo()))),
50    ));
51}
More examples
Hide additional examples
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: percent(100),
250                height: percent(100),
251                justify_content: JustifyContent::Center,
252                align_items: AlignItems::Center,
253                ..default()
254            },
255            children![(
256                Button,
257                Node {
258                    width: px(150),
259                    height: 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}
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: percent(100),
58                height: percent(100),
59                justify_content: JustifyContent::Center,
60                align_items: AlignItems::Center,
61                ..default()
62            },
63            children![(
64                Button,
65                Node {
66                    width: px(150),
67                    height: 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: percent(100),
163                    height: percent(100),
164                    justify_content: JustifyContent::Center,
165                    align_items: AlignItems::Center,
166                    ..default()
167                },
168                children![(
169                    Button,
170                    Node {
171                        width: px(150),
172                        height: 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.random_range(-400.0..400.0),
100            rng.random_range(0.0..400.0),
101            rng.random(),
102        );
103        let dir = rng.random_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.random();
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}
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);


#[derive(Component, Default)]
struct Mana {
    max: u32,
    current: u32,
}

fn level_up_system(mut commands: Commands, player: Res<PlayerEntity>) {
    // If a component already exists then modify it, otherwise insert a default value
    commands
        .entity(player.entity)
        .entry::<Level>()
        .and_modify(|mut lvl| lvl.0 += 1)
        .or_insert(Level(0));

    // Add a default value if none exists, and then modify the existing or new value
    commands
        .entity(player.entity)
        .entry::<Mana>()
        .or_default()
        .and_modify(|mut mana| {
            mana.max += 10;
            mana.current = mana.max;
    });
}
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 160)
157fn spawn_camera(commands: &mut Commands) {
158    commands
159        .spawn(Camera3d::default())
160        .insert(Transform::from_xyz(-0.7, 0.7, 1.0).looking_at(vec3(0.0, 0.3, 0.0), Vec3::Y));
161}
162
163/// Spawns the scene.
164///
165/// The scene is loaded from a glTF file.
166fn spawn_scene(commands: &mut Commands, asset_server: &AssetServer) {
167    commands
168        .spawn(SceneRoot(
169            asset_server.load(
170                GltfAssetLabel::Scene(0)
171                    .from_asset("models/MixedLightingExample/MixedLightingExample.gltf"),
172            ),
173        ))
174        .observe(
175            |_: On<SceneInstanceReady>,
176             mut lighting_mode_changed_writer: MessageWriter<LightingModeChanged>| {
177                // When the scene loads, send a `LightingModeChanged` event so
178                // that we set up the lightmaps.
179                lighting_mode_changed_writer.write(LightingModeChanged);
180            },
181        );
182}
183
184/// Spawns the buttons that allow the user to change the lighting mode.
185fn spawn_buttons(commands: &mut Commands) {
186    commands.spawn((
187        widgets::main_ui_node(),
188        children![widgets::option_buttons(
189            "Lighting",
190            &[
191                (LightingMode::Baked, "Baked"),
192                (LightingMode::MixedDirect, "Mixed (Direct)"),
193                (LightingMode::MixedIndirect, "Mixed (Indirect)"),
194                (LightingMode::RealTime, "Real-Time"),
195            ],
196        )],
197    ));
198}
199
200/// Spawns the help text at the top of the window.
201fn spawn_help_text(commands: &mut Commands, app_status: &AppStatus) {
202    commands.spawn((
203        create_help_text(app_status),
204        Node {
205            position_type: PositionType::Absolute,
206            top: px(12),
207            left: px(12),
208            ..default()
209        },
210        HelpText,
211    ));
212}
213
214/// Adds lightmaps to and/or removes lightmaps from objects in the scene when
215/// the lighting mode changes.
216///
217/// This is also called right after the scene loads in order to set up the
218/// lightmaps.
219fn update_lightmaps(
220    mut commands: Commands,
221    asset_server: Res<AssetServer>,
222    mut materials: ResMut<Assets<StandardMaterial>>,
223    meshes: Query<(Entity, &GltfMeshName, &MeshMaterial3d<StandardMaterial>), With<Mesh3d>>,
224    mut lighting_mode_changed_reader: MessageReader<LightingModeChanged>,
225    app_status: Res<AppStatus>,
226) {
227    // Only run if the lighting mode changed. (Note that a change event is fired
228    // when the scene first loads.)
229    if lighting_mode_changed_reader.read().next().is_none() {
230        return;
231    }
232
233    // Select the lightmap to use, based on the lighting mode.
234    let lightmap: Option<Handle<Image>> = match app_status.lighting_mode {
235        LightingMode::Baked => {
236            Some(asset_server.load("lightmaps/MixedLightingExample-Baked.zstd.ktx2"))
237        }
238        LightingMode::MixedDirect => {
239            Some(asset_server.load("lightmaps/MixedLightingExample-MixedDirect.zstd.ktx2"))
240        }
241        LightingMode::MixedIndirect => {
242            Some(asset_server.load("lightmaps/MixedLightingExample-MixedIndirect.zstd.ktx2"))
243        }
244        LightingMode::RealTime => None,
245    };
246
247    'outer: for (entity, name, material) in &meshes {
248        // Add lightmaps to or remove lightmaps from the scenery objects in the
249        // scene (all objects but the sphere).
250        //
251        // Note that doing a linear search through the `LIGHTMAPS` array is
252        // inefficient, but we do it anyway in this example to improve clarity.
253        for (lightmap_name, uv_rect) in LIGHTMAPS {
254            if &**name != lightmap_name {
255                continue;
256            }
257
258            // Lightmap exposure defaults to zero, so we need to set it.
259            if let Some(ref mut material) = materials.get_mut(material) {
260                material.lightmap_exposure = LIGHTMAP_EXPOSURE;
261            }
262
263            // Add or remove the lightmap.
264            match lightmap {
265                Some(ref lightmap) => {
266                    commands.entity(entity).insert(Lightmap {
267                        image: (*lightmap).clone(),
268                        uv_rect,
269                        bicubic_sampling: false,
270                    });
271                }
272                None => {
273                    commands.entity(entity).remove::<Lightmap>();
274                }
275            }
276            continue 'outer;
277        }
278
279        // Add lightmaps to or remove lightmaps from the sphere.
280        if &**name == "Sphere" {
281            // Lightmap exposure defaults to zero, so we need to set it.
282            if let Some(ref mut material) = materials.get_mut(material) {
283                material.lightmap_exposure = LIGHTMAP_EXPOSURE;
284            }
285
286            // Add or remove the lightmap from the sphere. We only apply the
287            // lightmap in fully-baked mode.
288            match (&lightmap, app_status.lighting_mode) {
289                (Some(lightmap), LightingMode::Baked) => {
290                    commands.entity(entity).insert(Lightmap {
291                        image: (*lightmap).clone(),
292                        uv_rect: SPHERE_UV_RECT,
293                        bicubic_sampling: false,
294                    });
295                }
296                _ => {
297                    commands.entity(entity).remove::<Lightmap>();
298                }
299            }
300        }
301    }
302}
303
304/// Converts a uv rectangle from the OpenGL coordinate system (origin in the
305/// lower left) to the Vulkan coordinate system (origin in the upper left) that
306/// Bevy uses.
307///
308/// For this particular example, the baking tool happened to use the OpenGL
309/// coordinate system, so it was more convenient to do the conversion at compile
310/// time than to pre-calculate and hard-code the values.
311const fn uv_rect_opengl(gl_min: Vec2, size: Vec2) -> Rect {
312    let min = vec2(gl_min.x, 1.0 - gl_min.y - size.y);
313    Rect {
314        min,
315        max: vec2(min.x + size.x, min.y + size.y),
316    }
317}
318
319/// Ensures that clicking on the scene to move the sphere doesn't result in a
320/// hit on the sphere itself.
321fn make_sphere_nonpickable(
322    mut commands: Commands,
323    mut query: Query<(Entity, &Name), (With<Mesh3d>, Without<Pickable>)>,
324) {
325    for (sphere, name) in &mut query {
326        if &**name == "Sphere" {
327            commands.entity(sphere).insert(Pickable::IGNORE);
328        }
329    }
330}
331
332/// Updates the directional light settings as necessary when the lighting mode
333/// changes.
334fn update_directional_light(
335    mut lights: Query<&mut DirectionalLight>,
336    mut lighting_mode_changed_reader: MessageReader<LightingModeChanged>,
337    app_status: Res<AppStatus>,
338) {
339    // Only run if the lighting mode changed. (Note that a change event is fired
340    // when the scene first loads.)
341    if lighting_mode_changed_reader.read().next().is_none() {
342        return;
343    }
344
345    // Real-time direct light is used on the scenery if we're using mixed
346    // indirect or real-time mode.
347    let scenery_is_lit_in_real_time = matches!(
348        app_status.lighting_mode,
349        LightingMode::MixedIndirect | LightingMode::RealTime
350    );
351
352    for mut light in &mut lights {
353        light.affects_lightmapped_mesh_diffuse = scenery_is_lit_in_real_time;
354        // Don't bother enabling shadows if they won't show up on the scenery.
355        light.shadows_enabled = scenery_is_lit_in_real_time;
356    }
357}
358
359/// Updates the state of the selection widgets at the bottom of the window when
360/// the lighting mode changes.
361fn update_radio_buttons(
362    mut widgets: Query<
363        (
364            Entity,
365            Option<&mut BackgroundColor>,
366            Has<Text>,
367            &WidgetClickSender<LightingMode>,
368        ),
369        Or<(With<RadioButton>, With<RadioButtonText>)>,
370    >,
371    app_status: Res<AppStatus>,
372    mut writer: TextUiWriter,
373) {
374    for (entity, image, has_text, sender) in &mut widgets {
375        let selected = **sender == app_status.lighting_mode;
376
377        if let Some(mut bg_color) = image {
378            widgets::update_ui_radio_button(&mut bg_color, selected);
379        }
380        if has_text {
381            widgets::update_ui_radio_button_text(entity, &mut writer, selected);
382        }
383    }
384}
385
386/// Handles clicks on the widgets at the bottom of the screen and fires
387/// [`LightingModeChanged`] events.
388fn handle_lighting_mode_change(
389    mut widget_click_event_reader: MessageReader<WidgetClickEvent<LightingMode>>,
390    mut lighting_mode_changed_writer: MessageWriter<LightingModeChanged>,
391    mut app_status: ResMut<AppStatus>,
392) {
393    for event in widget_click_event_reader.read() {
394        app_status.lighting_mode = **event;
395        lighting_mode_changed_writer.write(LightingModeChanged);
396    }
397}
398
399/// Moves the sphere to its original position when the user selects the baked
400/// lighting mode.
401///
402/// As the light from the sphere is precomputed and depends on the sphere's
403/// original position, the sphere must be placed there in order for the lighting
404/// to be correct.
405fn reset_sphere_position(
406    mut objects: Query<(&Name, &mut Transform)>,
407    mut lighting_mode_changed_reader: MessageReader<LightingModeChanged>,
408    app_status: Res<AppStatus>,
409) {
410    // Only run if the lighting mode changed and if the lighting mode is
411    // `LightingMode::Baked`. (Note that a change event is fired when the scene
412    // first loads.)
413    if lighting_mode_changed_reader.read().next().is_none()
414        || app_status.lighting_mode != LightingMode::Baked
415    {
416        return;
417    }
418
419    for (name, mut transform) in &mut objects {
420        if &**name == "Sphere" {
421            transform.translation = INITIAL_SPHERE_POSITION;
422            break;
423        }
424    }
425}
426
427/// Updates the position of the sphere when the user clicks on a spot in the
428/// scene.
429///
430/// Note that the position of the sphere is locked in baked lighting mode.
431fn move_sphere(
432    mouse_button_input: Res<ButtonInput<MouseButton>>,
433    pointers: Query<&PointerInteraction>,
434    mut meshes: Query<(&GltfMeshName, &ChildOf), With<Mesh3d>>,
435    mut transforms: Query<&mut Transform>,
436    app_status: Res<AppStatus>,
437) {
438    // Only run when the left button is clicked and we're not in baked lighting
439    // mode.
440    if app_status.lighting_mode == LightingMode::Baked
441        || !mouse_button_input.pressed(MouseButton::Left)
442    {
443        return;
444    }
445
446    // Find the sphere.
447    let Some(child_of) = meshes
448        .iter_mut()
449        .filter_map(|(name, child_of)| {
450            if &**name == "Sphere" {
451                Some(child_of)
452            } else {
453                None
454            }
455        })
456        .next()
457    else {
458        return;
459    };
460
461    // Grab its transform.
462    let Ok(mut transform) = transforms.get_mut(child_of.parent()) else {
463        return;
464    };
465
466    // Set its transform to the appropriate position, as determined by the
467    // picking subsystem.
468    for interaction in pointers.iter() {
469        if let Some(&(
470            _,
471            HitData {
472                position: Some(position),
473                ..
474            },
475        )) = interaction.get_nearest_hit()
476        {
477            transform.translation = position + vec3(0.0, SPHERE_OFFSET, 0.0);
478        }
479    }
480}
481
482/// Changes the help text at the top of the screen when the lighting mode
483/// changes.
484fn adjust_help_text(
485    mut commands: Commands,
486    help_texts: Query<Entity, With<HelpText>>,
487    app_status: Res<AppStatus>,
488    mut lighting_mode_changed_reader: MessageReader<LightingModeChanged>,
489) {
490    if lighting_mode_changed_reader.read().next().is_none() {
491        return;
492    }
493
494    for help_text in &help_texts {
495        commands
496            .entity(help_text)
497            .insert(create_help_text(&app_status));
498    }
499}
More examples
Hide additional examples
examples/3d/clustered_decals.rs (line 212)
209fn spawn_camera(commands: &mut Commands) {
210    commands
211        .spawn(Camera3d::default())
212        .insert(Transform::from_xyz(0.0, 2.5, 9.0).looking_at(Vec3::ZERO, Vec3::Y))
213        // Tag the camera with `Selection::Camera`.
214        .insert(Selection::Camera);
215}
216
217/// Spawns the actual clustered decals.
218fn spawn_decals(commands: &mut Commands, asset_server: &AssetServer) {
219    let image = asset_server.load("branding/icon.png");
220
221    commands.spawn((
222        ClusteredDecal {
223            image: image.clone(),
224            // Tint with red.
225            tag: 1,
226        },
227        calculate_initial_decal_transform(vec3(1.0, 3.0, 5.0), Vec3::ZERO, Vec2::splat(1.1)),
228        Selection::DecalA,
229    ));
230
231    commands.spawn((
232        ClusteredDecal {
233            image: image.clone(),
234            // Tint with blue.
235            tag: 2,
236        },
237        calculate_initial_decal_transform(vec3(-2.0, -1.0, 4.0), Vec3::ZERO, Vec2::splat(2.0)),
238        Selection::DecalB,
239    ));
240}
241
242/// Spawns the buttons at the bottom of the screen.
243fn spawn_buttons(commands: &mut Commands) {
244    // Spawn the radio buttons that allow the user to select an object to
245    // control.
246    commands.spawn((
247        widgets::main_ui_node(),
248        children![widgets::option_buttons(
249            "Drag to Move",
250            &[
251                (Selection::Camera, "Camera"),
252                (Selection::DecalA, "Decal A"),
253                (Selection::DecalB, "Decal B"),
254            ],
255        )],
256    ));
257
258    // Spawn the drag buttons that allow the user to control the scale and roll
259    // of the selected object.
260    commands.spawn((
261        Node {
262            flex_direction: FlexDirection::Row,
263            position_type: PositionType::Absolute,
264            right: px(10),
265            bottom: px(10),
266            column_gap: px(6),
267            ..default()
268        },
269        children![
270            (drag_button("Scale"), DragMode::Scale),
271            (drag_button("Roll"), DragMode::Roll),
272        ],
273    ));
274}
275
276/// Spawns a button that the user can drag to change a parameter.
277fn drag_button(label: &str) -> impl Bundle {
278    (
279        Node {
280            border: BUTTON_BORDER,
281            justify_content: JustifyContent::Center,
282            align_items: AlignItems::Center,
283            padding: BUTTON_PADDING,
284            ..default()
285        },
286        Button,
287        BackgroundColor(Color::BLACK),
288        BorderRadius::all(BUTTON_BORDER_RADIUS_SIZE),
289        BUTTON_BORDER_COLOR,
290        children![widgets::ui_text(label, Color::WHITE)],
291    )
292}
293
294/// Spawns the help text at the top of the screen.
295fn spawn_help_text(commands: &mut Commands, app_status: &AppStatus) {
296    commands.spawn((
297        Text::new(create_help_string(app_status)),
298        Node {
299            position_type: PositionType::Absolute,
300            top: px(12),
301            left: px(12),
302            ..default()
303        },
304        HelpText,
305    ));
306}
307
308/// Draws the outlines that show the bounds of the clustered decals.
309fn draw_gizmos(
310    mut gizmos: Gizmos,
311    decals: Query<(&GlobalTransform, &Selection), With<ClusteredDecal>>,
312) {
313    for (global_transform, selection) in &decals {
314        let color = match *selection {
315            Selection::Camera => continue,
316            Selection::DecalA => ORANGE_RED,
317            Selection::DecalB => LIME,
318        };
319
320        gizmos.primitive_3d(
321            &Cuboid {
322                // Since the clustered decal is a 1×1×1 cube in model space, its
323                // half-size is half of the scaling part of its transform.
324                half_size: global_transform.scale() * 0.5,
325            },
326            Isometry3d {
327                rotation: global_transform.rotation(),
328                translation: global_transform.translation_vec3a(),
329            },
330            color,
331        );
332    }
333}
334
335/// Calculates the initial transform of the clustered decal.
336fn calculate_initial_decal_transform(start: Vec3, looking_at: Vec3, size: Vec2) -> Transform {
337    let direction = looking_at - start;
338    let center = start + direction * 0.5;
339    Transform::from_translation(center)
340        .with_scale((size * 0.5).extend(direction.length()))
341        .looking_to(direction, Vec3::Y)
342}
343
344/// Rotates the cube a bit every frame.
345fn rotate_cube(mut meshes: Query<&mut Transform, With<Mesh3d>>) {
346    for mut transform in &mut meshes {
347        transform.rotate_y(CUBE_ROTATION_SPEED);
348    }
349}
350
351/// Updates the state of the radio buttons when the user clicks on one.
352fn update_radio_buttons(
353    mut widgets: Query<(
354        Entity,
355        Option<&mut BackgroundColor>,
356        Has<Text>,
357        &WidgetClickSender<Selection>,
358    )>,
359    app_status: Res<AppStatus>,
360    mut writer: TextUiWriter,
361) {
362    for (entity, maybe_bg_color, has_text, sender) in &mut widgets {
363        let selected = app_status.selection == **sender;
364        if let Some(mut bg_color) = maybe_bg_color {
365            widgets::update_ui_radio_button(&mut bg_color, selected);
366        }
367        if has_text {
368            widgets::update_ui_radio_button_text(entity, &mut writer, selected);
369        }
370    }
371}
372
373/// Changes the selection when the user clicks a radio button.
374fn handle_selection_change(
375    mut events: MessageReader<WidgetClickEvent<Selection>>,
376    mut app_status: ResMut<AppStatus>,
377) {
378    for event in events.read() {
379        app_status.selection = **event;
380    }
381}
382
383/// Process a drag event that moves the selected object.
384fn process_move_input(
385    mut selections: Query<(&mut Transform, &Selection)>,
386    mouse_buttons: Res<ButtonInput<MouseButton>>,
387    mouse_motion: Res<AccumulatedMouseMotion>,
388    app_status: Res<AppStatus>,
389) {
390    // Only process drags when movement is selected.
391    if !mouse_buttons.pressed(MouseButton::Left) || app_status.drag_mode != DragMode::Move {
392        return;
393    }
394
395    for (mut transform, selection) in &mut selections {
396        if app_status.selection != *selection {
397            continue;
398        }
399
400        let position = transform.translation;
401
402        // Convert to spherical coordinates.
403        let radius = position.length();
404        let mut theta = acos(position.y / radius);
405        let mut phi = position.z.signum() * acos(position.x * position.xz().length_recip());
406
407        // Camera movement is the inverse of object movement.
408        let (phi_factor, theta_factor) = match *selection {
409            Selection::Camera => (1.0, -1.0),
410            Selection::DecalA | Selection::DecalB => (-1.0, 1.0),
411        };
412
413        // Adjust the spherical coordinates. Clamp the inclination to (0, π).
414        phi += phi_factor * mouse_motion.delta.x * MOVE_SPEED;
415        theta = f32::clamp(
416            theta + theta_factor * mouse_motion.delta.y * MOVE_SPEED,
417            0.001,
418            PI - 0.001,
419        );
420
421        // Convert spherical coordinates back to Cartesian coordinates.
422        transform.translation =
423            radius * vec3(sin(theta) * cos(phi), cos(theta), sin(theta) * sin(phi));
424
425        // Look at the center, but preserve the previous roll angle.
426        let roll = transform.rotation.to_euler(EulerRot::YXZ).2;
427        transform.look_at(Vec3::ZERO, Vec3::Y);
428        let (yaw, pitch, _) = transform.rotation.to_euler(EulerRot::YXZ);
429        transform.rotation = Quat::from_euler(EulerRot::YXZ, yaw, pitch, roll);
430    }
431}
432
433/// Processes a drag event that scales the selected target.
434fn process_scale_input(
435    mut selections: Query<(&mut Transform, &Selection)>,
436    mouse_buttons: Res<ButtonInput<MouseButton>>,
437    mouse_motion: Res<AccumulatedMouseMotion>,
438    app_status: Res<AppStatus>,
439) {
440    // Only process drags when the scaling operation is selected.
441    if !mouse_buttons.pressed(MouseButton::Left) || app_status.drag_mode != DragMode::Scale {
442        return;
443    }
444
445    for (mut transform, selection) in &mut selections {
446        if app_status.selection == *selection {
447            transform.scale *= 1.0 + mouse_motion.delta.x * SCALE_SPEED;
448        }
449    }
450}
451
452/// Processes a drag event that rotates the selected target along its local Z
453/// axis.
454fn process_roll_input(
455    mut selections: Query<(&mut Transform, &Selection)>,
456    mouse_buttons: Res<ButtonInput<MouseButton>>,
457    mouse_motion: Res<AccumulatedMouseMotion>,
458    app_status: Res<AppStatus>,
459) {
460    // Only process drags when the rolling operation is selected.
461    if !mouse_buttons.pressed(MouseButton::Left) || app_status.drag_mode != DragMode::Roll {
462        return;
463    }
464
465    for (mut transform, selection) in &mut selections {
466        if app_status.selection != *selection {
467            continue;
468        }
469
470        let (yaw, pitch, mut roll) = transform.rotation.to_euler(EulerRot::YXZ);
471        roll += mouse_motion.delta.x * ROLL_SPEED;
472        transform.rotation = Quat::from_euler(EulerRot::YXZ, yaw, pitch, roll);
473    }
474}
475
476/// Creates the help string at the top left of the screen.
477fn create_help_string(app_status: &AppStatus) -> String {
478    format!(
479        "Click and drag to {} {}",
480        app_status.drag_mode, app_status.selection
481    )
482}
483
484/// Changes the drag mode when the user hovers over the "Scale" and "Roll"
485/// buttons in the lower right.
486///
487/// If the user is hovering over no such button, this system changes the drag
488/// mode back to its default value of [`DragMode::Move`].
489fn switch_drag_mode(
490    mut commands: Commands,
491    mut interactions: Query<(&Interaction, &DragMode)>,
492    mut windows: Query<Entity, With<Window>>,
493    mouse_buttons: Res<ButtonInput<MouseButton>>,
494    mut app_status: ResMut<AppStatus>,
495) {
496    if mouse_buttons.pressed(MouseButton::Left) {
497        return;
498    }
499
500    for (interaction, drag_mode) in &mut interactions {
501        if *interaction != Interaction::Hovered {
502            continue;
503        }
504
505        app_status.drag_mode = *drag_mode;
506
507        // Set the cursor to provide the user with a nice visual hint.
508        for window in &mut windows {
509            commands
510                .entity(window)
511                .insert(CursorIcon::from(SystemCursorIcon::EwResize));
512        }
513        return;
514    }
515
516    app_status.drag_mode = DragMode::Move;
517
518    for window in &mut windows {
519        commands.entity(window).remove::<CursorIcon>();
520    }
521}
examples/3d/light_textures.rs (line 223)
220fn spawn_camera(commands: &mut Commands) {
221    commands
222        .spawn(Camera3d::default())
223        .insert(Transform::from_xyz(0.0, 2.5, 9.0).looking_at(Vec3::ZERO, Vec3::Y))
224        // Tag the camera with `Selection::Camera`.
225        .insert(Selection::Camera);
226}
227
228fn spawn_light_textures(
229    commands: &mut Commands,
230    asset_server: &AssetServer,
231    meshes: &mut Assets<Mesh>,
232    materials: &mut Assets<StandardMaterial>,
233) {
234    commands.spawn((
235        SpotLight {
236            color: Color::srgb(1.0, 1.0, 0.8),
237            intensity: 10e6,
238            outer_angle: 0.25,
239            inner_angle: 0.25,
240            shadows_enabled: true,
241            ..default()
242        },
243        Transform::from_translation(Vec3::new(6.0, 1.0, 2.0)).looking_at(Vec3::ZERO, Vec3::Y),
244        SpotLightTexture {
245            image: asset_server.load("lightmaps/torch_spotlight_texture.png"),
246        },
247        Visibility::Inherited,
248        Selection::SpotLight,
249    ));
250
251    commands.spawn((
252        Visibility::Hidden,
253        Transform::from_translation(Vec3::new(0.0, 1.8, 0.01)).with_scale(Vec3::splat(0.1)),
254        Selection::PointLight,
255        children![
256            SceneRoot(
257                asset_server.load(GltfAssetLabel::Scene(0).from_asset("models/Faces/faces.glb")),
258            ),
259            (
260                Mesh3d(meshes.add(Sphere::new(1.0))),
261                MeshMaterial3d(materials.add(StandardMaterial {
262                    emissive: Color::srgb(0.0, 0.0, 300.0).to_linear(),
263                    ..default()
264                })),
265            ),
266            (
267                PointLight {
268                    color: Color::srgb(0.0, 0.0, 1.0),
269                    intensity: 1e6,
270                    shadows_enabled: true,
271                    ..default()
272                },
273                PointLightTexture {
274                    image: asset_server.load("lightmaps/faces_pointlight_texture_blurred.png"),
275                    cubemap_layout: CubemapLayout::CrossVertical,
276                },
277            )
278        ],
279    ));
280}
281
282/// Spawns the buttons at the bottom of the screen.
283fn spawn_buttons(commands: &mut Commands) {
284    // Spawn the radio buttons that allow the user to select an object to
285    // control.
286    commands.spawn((
287        widgets::main_ui_node(),
288        children![widgets::option_buttons(
289            "Drag to Move",
290            &[
291                (Selection::Camera, "Camera"),
292                (Selection::SpotLight, "Spotlight"),
293                (Selection::PointLight, "Point Light"),
294                (Selection::DirectionalLight, "Directional Light"),
295            ],
296        )],
297    ));
298
299    // Spawn the drag buttons that allow the user to control the scale and roll
300    // of the selected object.
301    commands.spawn((
302        Node {
303            flex_direction: FlexDirection::Row,
304            position_type: PositionType::Absolute,
305            right: px(10),
306            bottom: px(10),
307            column_gap: px(6),
308            ..default()
309        },
310        children![
311            widgets::option_buttons(
312                "",
313                &[
314                    (Visibility::Inherited, "Show"),
315                    (Visibility::Hidden, "Hide"),
316                ],
317            ),
318            (drag_button("Scale"), DragMode::Scale),
319            (drag_button("Roll"), DragMode::Roll),
320        ],
321    ));
322}
323
324/// Spawns a button that the user can drag to change a parameter.
325fn drag_button(label: &str) -> impl Bundle {
326    (
327        Node {
328            border: BUTTON_BORDER,
329            justify_content: JustifyContent::Center,
330            align_items: AlignItems::Center,
331            padding: BUTTON_PADDING,
332            ..default()
333        },
334        Button,
335        BackgroundColor(Color::BLACK),
336        BorderRadius::all(BUTTON_BORDER_RADIUS_SIZE),
337        BUTTON_BORDER_COLOR,
338        children![widgets::ui_text(label, Color::WHITE),],
339    )
340}
341
342/// Spawns the help text at the top of the screen.
343fn spawn_help_text(commands: &mut Commands, app_status: &AppStatus) {
344    commands.spawn((
345        Text::new(create_help_string(app_status)),
346        Node {
347            position_type: PositionType::Absolute,
348            top: px(12),
349            left: px(12),
350            ..default()
351        },
352        HelpText,
353    ));
354}
355
356/// Draws the outlines that show the bounds of the spotlight.
357fn draw_gizmos(mut gizmos: Gizmos, spotlight: Query<(&GlobalTransform, &SpotLight, &Visibility)>) {
358    if let Ok((global_transform, spotlight, visibility)) = spotlight.single()
359        && visibility != Visibility::Hidden
360    {
361        gizmos.primitive_3d(
362            &Cone::new(7.0 * spotlight.outer_angle, 7.0),
363            Isometry3d {
364                rotation: global_transform.rotation() * Quat::from_rotation_x(FRAC_PI_2),
365                translation: global_transform.translation_vec3a() * 0.5,
366            },
367            YELLOW,
368        );
369    }
370}
371
372/// Rotates the cube a bit every frame.
373fn rotate_cube(mut meshes: Query<&mut Transform, With<Rotate>>) {
374    for mut transform in &mut meshes {
375        transform.rotate_y(CUBE_ROTATION_SPEED);
376    }
377}
378
379/// Hide shadows on all meshes except the main cube
380fn hide_shadows(
381    mut commands: Commands,
382    meshes: Query<Entity, (With<Mesh3d>, Without<NotShadowCaster>, Without<Rotate>)>,
383) {
384    for ent in &meshes {
385        commands.entity(ent).insert(NotShadowCaster);
386    }
387}
388
389/// Updates the state of the radio buttons when the user clicks on one.
390fn update_radio_buttons(
391    mut widgets: Query<(
392        Entity,
393        Option<&mut BackgroundColor>,
394        Has<Text>,
395        &WidgetClickSender<Selection>,
396    )>,
397    app_status: Res<AppStatus>,
398    mut writer: TextUiWriter,
399    visible: Query<(&Visibility, &Selection)>,
400    mut visibility_widgets: Query<
401        (
402            Entity,
403            Option<&mut BackgroundColor>,
404            Has<Text>,
405            &WidgetClickSender<Visibility>,
406        ),
407        Without<WidgetClickSender<Selection>>,
408    >,
409) {
410    for (entity, maybe_bg_color, has_text, sender) in &mut widgets {
411        let selected = app_status.selection == **sender;
412        if let Some(mut bg_color) = maybe_bg_color {
413            widgets::update_ui_radio_button(&mut bg_color, selected);
414        }
415        if has_text {
416            widgets::update_ui_radio_button_text(entity, &mut writer, selected);
417        }
418    }
419
420    let visibility = visible
421        .iter()
422        .filter(|(_, selection)| **selection == app_status.selection)
423        .map(|(visibility, _)| *visibility)
424        .next()
425        .unwrap_or_default();
426    for (entity, maybe_bg_color, has_text, sender) in &mut visibility_widgets {
427        if let Some(mut bg_color) = maybe_bg_color {
428            widgets::update_ui_radio_button(&mut bg_color, **sender == visibility);
429        }
430        if has_text {
431            widgets::update_ui_radio_button_text(entity, &mut writer, **sender == visibility);
432        }
433    }
434}
435
436/// Changes the selection when the user clicks a radio button.
437fn handle_selection_change(
438    mut events: MessageReader<WidgetClickEvent<Selection>>,
439    mut app_status: ResMut<AppStatus>,
440) {
441    for event in events.read() {
442        app_status.selection = **event;
443    }
444}
445
446fn toggle_visibility(
447    mut events: MessageReader<WidgetClickEvent<Visibility>>,
448    app_status: Res<AppStatus>,
449    mut visibility: Query<(&mut Visibility, &Selection)>,
450) {
451    if let Some(vis) = events.read().last() {
452        for (mut visibility, selection) in visibility.iter_mut() {
453            if selection == &app_status.selection {
454                *visibility = **vis;
455            }
456        }
457    }
458}
459
460/// Process a drag event that moves the selected object.
461fn process_move_input(
462    mut selections: Query<(&mut Transform, &Selection)>,
463    mouse_buttons: Res<ButtonInput<MouseButton>>,
464    mouse_motion: Res<AccumulatedMouseMotion>,
465    app_status: Res<AppStatus>,
466) {
467    // Only process drags when movement is selected.
468    if !mouse_buttons.pressed(MouseButton::Left) || app_status.drag_mode != DragMode::Move {
469        return;
470    }
471
472    for (mut transform, selection) in &mut selections {
473        if app_status.selection != *selection {
474            continue;
475        }
476
477        // use simple movement for the point light
478        if *selection == Selection::PointLight {
479            transform.translation +=
480                (mouse_motion.delta * Vec2::new(1.0, -1.0) * MOVE_SPEED).extend(0.0);
481            return;
482        }
483
484        let position = transform.translation;
485
486        // Convert to spherical coordinates.
487        let radius = position.length();
488        let mut theta = acos(position.y / radius);
489        let mut phi = position.z.signum() * acos(position.x * position.xz().length_recip());
490
491        // Camera movement is the inverse of object movement.
492        let (phi_factor, theta_factor) = match *selection {
493            Selection::Camera => (1.0, -1.0),
494            _ => (-1.0, 1.0),
495        };
496
497        // Adjust the spherical coordinates. Clamp the inclination to (0, π).
498        phi += phi_factor * mouse_motion.delta.x * MOVE_SPEED;
499        theta = f32::clamp(
500            theta + theta_factor * mouse_motion.delta.y * MOVE_SPEED,
501            0.001,
502            PI - 0.001,
503        );
504
505        // Convert spherical coordinates back to Cartesian coordinates.
506        transform.translation =
507            radius * vec3(sin(theta) * cos(phi), cos(theta), sin(theta) * sin(phi));
508
509        // Look at the center, but preserve the previous roll angle.
510        let roll = transform.rotation.to_euler(EulerRot::YXZ).2;
511        transform.look_at(Vec3::ZERO, Vec3::Y);
512        let (yaw, pitch, _) = transform.rotation.to_euler(EulerRot::YXZ);
513        transform.rotation = Quat::from_euler(EulerRot::YXZ, yaw, pitch, roll);
514    }
515}
516
517/// Processes a drag event that scales the selected target.
518fn process_scale_input(
519    mut scale_selections: Query<(&mut Transform, &Selection)>,
520    mut spotlight_selections: Query<(&mut SpotLight, &Selection)>,
521    mouse_buttons: Res<ButtonInput<MouseButton>>,
522    mouse_motion: Res<AccumulatedMouseMotion>,
523    app_status: Res<AppStatus>,
524) {
525    // Only process drags when the scaling operation is selected.
526    if !mouse_buttons.pressed(MouseButton::Left) || app_status.drag_mode != DragMode::Scale {
527        return;
528    }
529
530    for (mut transform, selection) in &mut scale_selections {
531        if app_status.selection == *selection {
532            transform.scale = (transform.scale * (1.0 + mouse_motion.delta.x * SCALE_SPEED))
533                .clamp(Vec3::splat(0.01), Vec3::splat(5.0));
534        }
535    }
536
537    for (mut spotlight, selection) in &mut spotlight_selections {
538        if app_status.selection == *selection {
539            spotlight.outer_angle = (spotlight.outer_angle
540                * (1.0 + mouse_motion.delta.x * SCALE_SPEED))
541                .clamp(0.01, FRAC_PI_4);
542            spotlight.inner_angle = spotlight.outer_angle;
543        }
544    }
545}
546
547/// Processes a drag event that rotates the selected target along its local Z
548/// axis.
549fn process_roll_input(
550    mut selections: Query<(&mut Transform, &Selection)>,
551    mouse_buttons: Res<ButtonInput<MouseButton>>,
552    mouse_motion: Res<AccumulatedMouseMotion>,
553    app_status: Res<AppStatus>,
554) {
555    // Only process drags when the rolling operation is selected.
556    if !mouse_buttons.pressed(MouseButton::Left) || app_status.drag_mode != DragMode::Roll {
557        return;
558    }
559
560    for (mut transform, selection) in &mut selections {
561        if app_status.selection != *selection {
562            continue;
563        }
564
565        let (yaw, pitch, mut roll) = transform.rotation.to_euler(EulerRot::YXZ);
566        roll += mouse_motion.delta.x * ROLL_SPEED;
567        transform.rotation = Quat::from_euler(EulerRot::YXZ, yaw, pitch, roll);
568    }
569}
570
571/// Creates the help string at the top left of the screen.
572fn create_help_string(app_status: &AppStatus) -> String {
573    format!(
574        "Click and drag to {} {}",
575        app_status.drag_mode, app_status.selection
576    )
577}
578
579/// Changes the drag mode when the user hovers over the "Scale" and "Roll"
580/// buttons in the lower right.
581///
582/// If the user is hovering over no such button, this system changes the drag
583/// mode back to its default value of [`DragMode::Move`].
584fn switch_drag_mode(
585    mut commands: Commands,
586    mut interactions: Query<(&Interaction, &DragMode)>,
587    mut windows: Query<Entity, With<Window>>,
588    mouse_buttons: Res<ButtonInput<MouseButton>>,
589    mut app_status: ResMut<AppStatus>,
590) {
591    if mouse_buttons.pressed(MouseButton::Left) {
592        return;
593    }
594
595    for (interaction, drag_mode) in &mut interactions {
596        if *interaction != Interaction::Hovered {
597            continue;
598        }
599
600        app_status.drag_mode = *drag_mode;
601
602        // Set the cursor to provide the user with a nice visual hint.
603        for window in &mut windows {
604            commands
605                .entity(window)
606                .insert(CursorIcon::from(SystemCursorIcon::EwResize));
607        }
608        return;
609    }
610
611    app_status.drag_mode = DragMode::Move;
612
613    for window in &mut windows {
614        commands.entity(window).remove::<CursorIcon>();
615    }
616}
617
618/// Updates the help text in the top left of the screen to reflect the current
619/// selection and drag mode.
620fn update_help_text(mut help_text: Query<&mut Text, With<HelpText>>, app_status: Res<AppStatus>) {
621    for mut text in &mut help_text {
622        text.0 = create_help_string(&app_status);
623    }
624}
625
626/// Updates the visibility of the drag mode buttons so that they aren't visible
627/// if the camera is selected.
628fn update_button_visibility(
629    mut nodes: Query<&mut Visibility, Or<(With<DragMode>, With<WidgetClickSender<Visibility>>)>>,
630    app_status: Res<AppStatus>,
631) {
632    for mut visibility in &mut nodes {
633        *visibility = match app_status.selection {
634            Selection::Camera => Visibility::Hidden,
635            _ => Visibility::Visible,
636        };
637    }
638}
639
640fn update_directional_light(
641    mut commands: Commands,
642    asset_server: Res<AssetServer>,
643    selections: Query<(&Selection, &Visibility)>,
644    mut light: Query<(
645        Entity,
646        &mut DirectionalLight,
647        Option<&DirectionalLightTexture>,
648    )>,
649) {
650    let directional_visible = selections
651        .iter()
652        .filter(|(selection, _)| **selection == Selection::DirectionalLight)
653        .any(|(_, visibility)| visibility != Visibility::Hidden);
654    let any_texture_light_visible = selections
655        .iter()
656        .filter(|(selection, _)| {
657            **selection == Selection::PointLight || **selection == Selection::SpotLight
658        })
659        .any(|(_, visibility)| visibility != Visibility::Hidden);
660
661    let (entity, mut light, maybe_texture) = light
662        .single_mut()
663        .expect("there should be a single directional light");
664
665    if directional_visible {
666        light.illuminance = AMBIENT_DAYLIGHT;
667        if maybe_texture.is_none() {
668            commands.entity(entity).insert(DirectionalLightTexture {
669                image: asset_server.load("lightmaps/caustic_directional_texture.png"),
670                tiled: true,
671            });
672        }
673    } else if any_texture_light_visible {
674        light.illuminance = CLEAR_SUNRISE;
675        if maybe_texture.is_some() {
676            commands.entity(entity).remove::<DirectionalLightTexture>();
677        }
678    } else {
679        light.illuminance = AMBIENT_DAYLIGHT;
680        if maybe_texture.is_some() {
681            commands.entity(entity).remove::<DirectionalLightTexture>();
682        }
683    }
684}
examples/ui/standard_widgets_observers.rs (line 462)
453fn update_widget_values(
454    res: Res<DemoWidgetStates>,
455    mut sliders: Query<Entity, With<DemoSlider>>,
456    mut commands: Commands,
457) {
458    if res.is_changed() {
459        for slider_ent in sliders.iter_mut() {
460            commands
461                .entity(slider_ent)
462                .insert(SliderValue(res.slider_value));
463        }
464    }
465}
466
467fn toggle_disabled(
468    input: Res<ButtonInput<KeyCode>>,
469    mut interaction_query: Query<
470        (Entity, Has<InteractionDisabled>),
471        Or<(With<Button>, With<Slider>, With<Checkbox>)>,
472    >,
473    mut commands: Commands,
474) {
475    if input.just_pressed(KeyCode::KeyD) {
476        for (entity, disabled) in &mut interaction_query {
477            if disabled {
478                info!("Widget enabled");
479                commands.entity(entity).remove::<InteractionDisabled>();
480            } else {
481                info!("Widget disabled");
482                commands.entity(entity).insert(InteractionDisabled);
483            }
484        }
485    }
486}
examples/3d/irradiance_volumes.rs (line 275)
268fn spawn_sphere(commands: &mut Commands, assets: &ExampleAssets) {
269    commands
270        .spawn((
271            Mesh3d(assets.main_sphere.clone()),
272            MeshMaterial3d(assets.main_sphere_material.clone()),
273            Transform::from_xyz(0.0, SPHERE_SCALE, 0.0).with_scale(Vec3::splat(SPHERE_SCALE)),
274        ))
275        .insert(MainObject);
276}
277
278fn spawn_voxel_cube_parent(commands: &mut Commands) {
279    commands.spawn((Visibility::Hidden, Transform::default(), VoxelCubeParent));
280}
281
282fn spawn_fox(commands: &mut Commands, assets: &ExampleAssets) {
283    commands.spawn((
284        SceneRoot(assets.fox.clone()),
285        Visibility::Hidden,
286        Transform::from_scale(Vec3::splat(FOX_SCALE)),
287        MainObject,
288    ));
289}
290
291fn spawn_text(commands: &mut Commands, app_status: &AppStatus) {
292    commands.spawn((
293        app_status.create_text(),
294        Node {
295            position_type: PositionType::Absolute,
296            bottom: px(12),
297            left: px(12),
298            ..default()
299        },
300    ));
301}
302
303// A system that updates the help text.
304fn update_text(mut text_query: Query<&mut Text>, app_status: Res<AppStatus>) {
305    for mut text in text_query.iter_mut() {
306        *text = app_status.create_text();
307    }
308}
309
310impl AppStatus {
311    // Constructs the help text at the bottom of the screen based on the
312    // application status.
313    fn create_text(&self) -> Text {
314        let irradiance_volume_help_text = if self.irradiance_volume_present {
315            DISABLE_IRRADIANCE_VOLUME_HELP_TEXT
316        } else {
317            ENABLE_IRRADIANCE_VOLUME_HELP_TEXT
318        };
319
320        let voxels_help_text = if self.voxels_visible {
321            HIDE_VOXELS_HELP_TEXT
322        } else {
323            SHOW_VOXELS_HELP_TEXT
324        };
325
326        let rotation_help_text = if self.rotating {
327            STOP_ROTATION_HELP_TEXT
328        } else {
329            START_ROTATION_HELP_TEXT
330        };
331
332        let switch_mesh_help_text = match self.model {
333            ExampleModel::Sphere => SWITCH_TO_FOX_HELP_TEXT,
334            ExampleModel::Fox => SWITCH_TO_SPHERE_HELP_TEXT,
335        };
336
337        format!(
338            "{CLICK_TO_MOVE_HELP_TEXT}\n\
339            {voxels_help_text}\n\
340            {irradiance_volume_help_text}\n\
341            {rotation_help_text}\n\
342            {switch_mesh_help_text}"
343        )
344        .into()
345    }
346}
347
348// Rotates the camera a bit every frame.
349fn rotate_camera(
350    mut camera_query: Query<&mut Transform, With<Camera3d>>,
351    time: Res<Time>,
352    app_status: Res<AppStatus>,
353) {
354    if !app_status.rotating {
355        return;
356    }
357
358    for mut transform in camera_query.iter_mut() {
359        transform.translation = Vec2::from_angle(ROTATION_SPEED * time.delta_secs())
360            .rotate(transform.translation.xz())
361            .extend(transform.translation.y)
362            .xzy();
363        transform.look_at(Vec3::ZERO, Vec3::Y);
364    }
365}
366
367// Toggles between the unskinned sphere model and the skinned fox model if the
368// user requests it.
369fn change_main_object(
370    keyboard: Res<ButtonInput<KeyCode>>,
371    mut app_status: ResMut<AppStatus>,
372    mut sphere_query: Query<&mut Visibility, (With<MainObject>, With<Mesh3d>, Without<SceneRoot>)>,
373    mut fox_query: Query<&mut Visibility, (With<MainObject>, With<SceneRoot>)>,
374) {
375    if !keyboard.just_pressed(KeyCode::Tab) {
376        return;
377    }
378    let Some(mut sphere_visibility) = sphere_query.iter_mut().next() else {
379        return;
380    };
381    let Some(mut fox_visibility) = fox_query.iter_mut().next() else {
382        return;
383    };
384
385    match app_status.model {
386        ExampleModel::Sphere => {
387            *sphere_visibility = Visibility::Hidden;
388            *fox_visibility = Visibility::Visible;
389            app_status.model = ExampleModel::Fox;
390        }
391        ExampleModel::Fox => {
392            *sphere_visibility = Visibility::Visible;
393            *fox_visibility = Visibility::Hidden;
394            app_status.model = ExampleModel::Sphere;
395        }
396    }
397}
398
399impl Default for AppStatus {
400    fn default() -> Self {
401        Self {
402            irradiance_volume_present: true,
403            rotating: true,
404            model: ExampleModel::Sphere,
405            voxels_visible: false,
406        }
407    }
408}
409
410// Turns on and off the irradiance volume as requested by the user.
411fn toggle_irradiance_volumes(
412    mut commands: Commands,
413    keyboard: Res<ButtonInput<KeyCode>>,
414    light_probe_query: Query<Entity, With<LightProbe>>,
415    mut app_status: ResMut<AppStatus>,
416    assets: Res<ExampleAssets>,
417    mut ambient_light: ResMut<AmbientLight>,
418) {
419    if !keyboard.just_pressed(KeyCode::Space) {
420        return;
421    };
422
423    let Some(light_probe) = light_probe_query.iter().next() else {
424        return;
425    };
426
427    if app_status.irradiance_volume_present {
428        commands.entity(light_probe).remove::<IrradianceVolume>();
429        ambient_light.brightness = AMBIENT_LIGHT_BRIGHTNESS * IRRADIANCE_VOLUME_INTENSITY;
430        app_status.irradiance_volume_present = false;
431    } else {
432        commands.entity(light_probe).insert(IrradianceVolume {
433            voxels: assets.irradiance_volume.clone(),
434            intensity: IRRADIANCE_VOLUME_INTENSITY,
435            ..default()
436        });
437        ambient_light.brightness = 0.0;
438        app_status.irradiance_volume_present = true;
439    }
440}
441
442fn toggle_rotation(keyboard: Res<ButtonInput<KeyCode>>, mut app_status: ResMut<AppStatus>) {
443    if keyboard.just_pressed(KeyCode::Enter) {
444        app_status.rotating = !app_status.rotating;
445    }
446}
447
448// Handles clicks on the plane that reposition the object.
449fn handle_mouse_clicks(
450    buttons: Res<ButtonInput<MouseButton>>,
451    windows: Query<&Window, With<PrimaryWindow>>,
452    cameras: Query<(&Camera, &GlobalTransform)>,
453    mut main_objects: Query<&mut Transform, With<MainObject>>,
454) {
455    if !buttons.pressed(MouseButton::Left) {
456        return;
457    }
458    let Some(mouse_position) = windows.iter().next().and_then(Window::cursor_position) else {
459        return;
460    };
461    let Some((camera, camera_transform)) = cameras.iter().next() else {
462        return;
463    };
464
465    // Figure out where the user clicked on the plane.
466    let Ok(ray) = camera.viewport_to_world(camera_transform, mouse_position) else {
467        return;
468    };
469    let Some(ray_distance) = ray.intersect_plane(Vec3::ZERO, InfinitePlane3d::new(Vec3::Y)) else {
470        return;
471    };
472    let plane_intersection = ray.origin + ray.direction.normalize() * ray_distance;
473
474    // Move all the main objects.
475    for mut transform in main_objects.iter_mut() {
476        transform.translation = vec3(
477            plane_intersection.x,
478            transform.translation.y,
479            plane_intersection.z,
480        );
481    }
482}
483
484impl FromWorld for ExampleAssets {
485    fn from_world(world: &mut World) -> Self {
486        let fox_animation =
487            world.load_asset(GltfAssetLabel::Animation(1).from_asset("models/animated/Fox.glb"));
488        let (fox_animation_graph, fox_animation_node) =
489            AnimationGraph::from_clip(fox_animation.clone());
490
491        ExampleAssets {
492            main_sphere: world.add_asset(Sphere::default().mesh().uv(32, 18)),
493            fox: world.load_asset(GltfAssetLabel::Scene(0).from_asset("models/animated/Fox.glb")),
494            main_sphere_material: world.add_asset(Color::from(SILVER)),
495            main_scene: world.load_asset(
496                GltfAssetLabel::Scene(0)
497                    .from_asset("models/IrradianceVolumeExample/IrradianceVolumeExample.glb"),
498            ),
499            irradiance_volume: world.load_asset("irradiance_volumes/Example.vxgi.ktx2"),
500            fox_animation_graph: world.add_asset(fox_animation_graph),
501            fox_animation_node,
502            voxel_cube: world.add_asset(Cuboid::default()),
503            // Just use a specular map for the skybox since it's not too blurry.
504            // In reality you wouldn't do this--you'd use a real skybox texture--but
505            // reusing the textures like this saves space in the Bevy repository.
506            skybox: world.load_asset("environment_maps/pisa_specular_rgb9e5_zstd.ktx2"),
507        }
508    }
509}
510
511// Plays the animation on the fox.
512fn play_animations(
513    mut commands: Commands,
514    assets: Res<ExampleAssets>,
515    mut players: Query<(Entity, &mut AnimationPlayer), Without<AnimationGraphHandle>>,
516) {
517    for (entity, mut player) in players.iter_mut() {
518        commands
519            .entity(entity)
520            .insert(AnimationGraphHandle(assets.fox_animation_graph.clone()));
521        player.play(assets.fox_animation_node).repeat();
522    }
523}
524
525fn create_cubes(
526    image_assets: Res<Assets<Image>>,
527    mut commands: Commands,
528    irradiance_volumes: Query<(&IrradianceVolume, &GlobalTransform)>,
529    voxel_cube_parents: Query<Entity, With<VoxelCubeParent>>,
530    voxel_cubes: Query<Entity, With<VoxelCube>>,
531    example_assets: Res<ExampleAssets>,
532    mut voxel_visualization_material_assets: ResMut<Assets<VoxelVisualizationMaterial>>,
533) {
534    // If voxel cubes have already been spawned, don't do anything.
535    if !voxel_cubes.is_empty() {
536        return;
537    }
538
539    let Some(voxel_cube_parent) = voxel_cube_parents.iter().next() else {
540        return;
541    };
542
543    for (irradiance_volume, global_transform) in irradiance_volumes.iter() {
544        let Some(image) = image_assets.get(&irradiance_volume.voxels) else {
545            continue;
546        };
547
548        let resolution = image.texture_descriptor.size;
549
550        let voxel_cube_material = voxel_visualization_material_assets.add(ExtendedMaterial {
551            base: StandardMaterial::from(Color::from(RED)),
552            extension: VoxelVisualizationExtension {
553                irradiance_volume_info: VoxelVisualizationIrradianceVolumeInfo {
554                    world_from_voxel: VOXEL_FROM_WORLD.inverse(),
555                    voxel_from_world: VOXEL_FROM_WORLD,
556                    resolution: uvec3(
557                        resolution.width,
558                        resolution.height,
559                        resolution.depth_or_array_layers,
560                    ),
561                    intensity: IRRADIANCE_VOLUME_INTENSITY,
562                },
563            },
564        });
565
566        let scale = vec3(
567            1.0 / resolution.width as f32,
568            1.0 / resolution.height as f32,
569            1.0 / resolution.depth_or_array_layers as f32,
570        );
571
572        // Spawn a cube for each voxel.
573        for z in 0..resolution.depth_or_array_layers {
574            for y in 0..resolution.height {
575                for x in 0..resolution.width {
576                    let uvw = (uvec3(x, y, z).as_vec3() + 0.5) * scale - 0.5;
577                    let pos = global_transform.transform_point(uvw);
578                    let voxel_cube = commands
579                        .spawn((
580                            Mesh3d(example_assets.voxel_cube.clone()),
581                            MeshMaterial3d(voxel_cube_material.clone()),
582                            Transform::from_scale(Vec3::splat(VOXEL_CUBE_SCALE))
583                                .with_translation(pos),
584                        ))
585                        .insert(VoxelCube)
586                        .insert(NotShadowCaster)
587                        .id();
588
589                    commands.entity(voxel_cube_parent).add_child(voxel_cube);
590                }
591            }
592        }
593    }
594}
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}
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 170)
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    let make_wheel = |x: f32, z: f32| {
140        (
141            Mesh3d(cylinder.clone()),
142            MeshMaterial3d(wheel_matl.clone()),
143            Transform::from_xyz(0.14 * x, -0.045, 0.15 * z)
144                .with_scale(Vec3::new(0.15, 0.04, 0.15))
145                .with_rotation(Quat::from_rotation_z(std::f32::consts::FRAC_PI_2)),
146            Rotates,
147        )
148    };
149
150    for i in 0..N_CARS {
151        let color = colors[i % colors.len()].clone();
152        commands
153            .spawn((
154                Mesh3d(box_mesh.clone()),
155                MeshMaterial3d(color.clone()),
156                Transform::from_scale(Vec3::splat(0.5)),
157                Moves(i as f32 * 2.0),
158                children![
159                    (
160                        Mesh3d(box_mesh.clone()),
161                        MeshMaterial3d(color),
162                        Transform::from_xyz(0.0, 0.08, 0.03).with_scale(Vec3::new(1.0, 1.0, 0.5)),
163                    ),
164                    make_wheel(1.0, 1.0),
165                    make_wheel(1.0, -1.0),
166                    make_wheel(-1.0, 1.0),
167                    make_wheel(-1.0, -1.0)
168                ],
169            ))
170            .insert_if(CameraTracked, || i == 0);
171    }
172}
More examples
Hide additional examples
examples/3d/ssao.rs (lines 111-117)
89fn update(
90    camera: Single<
91        (
92            Entity,
93            Option<&ScreenSpaceAmbientOcclusion>,
94            Option<&TemporalJitter>,
95        ),
96        With<Camera>,
97    >,
98    mut text: Single<&mut Text>,
99    mut sphere: Single<&mut Transform, With<SphereMarker>>,
100    mut commands: Commands,
101    keycode: Res<ButtonInput<KeyCode>>,
102    time: Res<Time>,
103) {
104    sphere.translation.y = ops::sin(time.elapsed_secs() / 1.7) * 0.7;
105
106    let (camera_entity, ssao, temporal_jitter) = *camera;
107    let current_ssao = ssao.cloned().unwrap_or_default();
108
109    let mut commands = commands.entity(camera_entity);
110    commands
111        .insert_if(
112            ScreenSpaceAmbientOcclusion {
113                quality_level: ScreenSpaceAmbientOcclusionQualityLevel::Low,
114                ..current_ssao
115            },
116            || keycode.just_pressed(KeyCode::Digit2),
117        )
118        .insert_if(
119            ScreenSpaceAmbientOcclusion {
120                quality_level: ScreenSpaceAmbientOcclusionQualityLevel::Medium,
121                ..current_ssao
122            },
123            || keycode.just_pressed(KeyCode::Digit3),
124        )
125        .insert_if(
126            ScreenSpaceAmbientOcclusion {
127                quality_level: ScreenSpaceAmbientOcclusionQualityLevel::High,
128                ..current_ssao
129            },
130            || keycode.just_pressed(KeyCode::Digit4),
131        )
132        .insert_if(
133            ScreenSpaceAmbientOcclusion {
134                quality_level: ScreenSpaceAmbientOcclusionQualityLevel::Ultra,
135                ..current_ssao
136            },
137            || keycode.just_pressed(KeyCode::Digit5),
138        )
139        .insert_if(
140            ScreenSpaceAmbientOcclusion {
141                constant_object_thickness: (current_ssao.constant_object_thickness * 2.0).min(4.0),
142                ..current_ssao
143            },
144            || keycode.just_pressed(KeyCode::ArrowUp),
145        )
146        .insert_if(
147            ScreenSpaceAmbientOcclusion {
148                constant_object_thickness: (current_ssao.constant_object_thickness * 0.5)
149                    .max(0.0625),
150                ..current_ssao
151            },
152            || keycode.just_pressed(KeyCode::ArrowDown),
153        );
154    if keycode.just_pressed(KeyCode::Digit1) {
155        commands.remove::<ScreenSpaceAmbientOcclusion>();
156    }
157    if keycode.just_pressed(KeyCode::Space) {
158        if temporal_jitter.is_some() {
159            commands.remove::<TemporalJitter>();
160        } else {
161            commands.insert(TemporalJitter::default());
162        }
163    }
164
165    text.clear();
166
167    let (o, l, m, h, u) = match ssao.map(|s| s.quality_level) {
168        None => ("*", "", "", "", ""),
169        Some(ScreenSpaceAmbientOcclusionQualityLevel::Low) => ("", "*", "", "", ""),
170        Some(ScreenSpaceAmbientOcclusionQualityLevel::Medium) => ("", "", "*", "", ""),
171        Some(ScreenSpaceAmbientOcclusionQualityLevel::High) => ("", "", "", "*", ""),
172        Some(ScreenSpaceAmbientOcclusionQualityLevel::Ultra) => ("", "", "", "", "*"),
173        _ => unreachable!(),
174    };
175
176    if let Some(thickness) = ssao.map(|s| s.constant_object_thickness) {
177        text.push_str(&format!(
178            "Constant object thickness: {thickness} (Up/Down)\n\n"
179        ));
180    }
181
182    text.push_str("SSAO Quality:\n");
183    text.push_str(&format!("(1) {o}Off{o}\n"));
184    text.push_str(&format!("(2) {l}Low{l}\n"));
185    text.push_str(&format!("(3) {m}Medium{m}\n"));
186    text.push_str(&format!("(4) {h}High{h}\n"));
187    text.push_str(&format!("(5) {u}Ultra{u}\n\n"));
188
189    text.push_str("Temporal Antialiasing:\n");
190    text.push_str(match temporal_jitter {
191        Some(_) => "(Space) Enabled",
192        None => "(Space) Disabled",
193    });
194}
examples/stress_tests/many_cubes.rs (line 181)
138fn setup(
139    mut commands: Commands,
140    args: Res<Args>,
141    mesh_assets: ResMut<Assets<Mesh>>,
142    material_assets: ResMut<Assets<StandardMaterial>>,
143    images: ResMut<Assets<Image>>,
144) {
145    warn!(include_str!("warning_string.txt"));
146
147    let args = args.into_inner();
148    let images = images.into_inner();
149    let material_assets = material_assets.into_inner();
150    let mesh_assets = mesh_assets.into_inner();
151
152    let meshes = init_meshes(args, mesh_assets);
153
154    let material_textures = init_textures(args, images);
155    let materials = init_materials(args, &material_textures, material_assets);
156
157    // We're seeding the PRNG here to make this example deterministic for testing purposes.
158    // This isn't strictly required in practical use unless you need your app to be deterministic.
159    let mut material_rng = ChaCha8Rng::seed_from_u64(42);
160    match args.layout {
161        Layout::Sphere => {
162            // NOTE: This pattern is good for testing performance of culling as it provides roughly
163            // the same number of visible meshes regardless of the viewing angle.
164            const N_POINTS: usize = WIDTH * HEIGHT * 4;
165            // NOTE: f64 is used to avoid precision issues that produce visual artifacts in the distribution
166            let radius = WIDTH as f64 * 2.5;
167            let golden_ratio = 0.5f64 * (1.0f64 + 5.0f64.sqrt());
168            for i in 0..N_POINTS {
169                let spherical_polar_theta_phi =
170                    fibonacci_spiral_on_sphere(golden_ratio, i, N_POINTS);
171                let unit_sphere_p = spherical_polar_to_cartesian(spherical_polar_theta_phi);
172                let (mesh, transform) = meshes.choose(&mut material_rng).unwrap();
173                commands
174                    .spawn((
175                        Mesh3d(mesh.clone()),
176                        MeshMaterial3d(materials.choose(&mut material_rng).unwrap().clone()),
177                        Transform::from_translation((radius * unit_sphere_p).as_vec3())
178                            .looking_at(Vec3::ZERO, Vec3::Y)
179                            .mul_transform(*transform),
180                    ))
181                    .insert_if(NoFrustumCulling, || args.no_frustum_culling)
182                    .insert_if(NoAutomaticBatching, || args.no_automatic_batching);
183            }
184
185            // camera
186            let mut camera = commands.spawn(Camera3d::default());
187            if args.no_indirect_drawing {
188                camera.insert(NoIndirectDrawing);
189            }
190            if args.no_cpu_culling {
191                camera.insert(NoCpuCulling);
192            }
193
194            // Inside-out box around the meshes onto which shadows are cast (though you cannot see them...)
195            commands.spawn((
196                Mesh3d(mesh_assets.add(Cuboid::from_size(Vec3::splat(radius as f32 * 2.2)))),
197                MeshMaterial3d(material_assets.add(StandardMaterial::from(Color::WHITE))),
198                Transform::from_scale(-Vec3::ONE),
199                NotShadowCaster,
200            ));
201        }
202        _ => {
203            // NOTE: This pattern is good for demonstrating that frustum culling is working correctly
204            // as the number of visible meshes rises and falls depending on the viewing angle.
205            let scale = 2.5;
206            for x in 0..WIDTH {
207                for y in 0..HEIGHT {
208                    // introduce spaces to break any kind of moiré pattern
209                    if x % 10 == 0 || y % 10 == 0 {
210                        continue;
211                    }
212                    // cube
213                    commands.spawn((
214                        Mesh3d(meshes.choose(&mut material_rng).unwrap().0.clone()),
215                        MeshMaterial3d(materials.choose(&mut material_rng).unwrap().clone()),
216                        Transform::from_xyz((x as f32) * scale, (y as f32) * scale, 0.0),
217                    ));
218                    commands.spawn((
219                        Mesh3d(meshes.choose(&mut material_rng).unwrap().0.clone()),
220                        MeshMaterial3d(materials.choose(&mut material_rng).unwrap().clone()),
221                        Transform::from_xyz(
222                            (x as f32) * scale,
223                            HEIGHT as f32 * scale,
224                            (y as f32) * scale,
225                        ),
226                    ));
227                    commands.spawn((
228                        Mesh3d(meshes.choose(&mut material_rng).unwrap().0.clone()),
229                        MeshMaterial3d(materials.choose(&mut material_rng).unwrap().clone()),
230                        Transform::from_xyz((x as f32) * scale, 0.0, (y as f32) * scale),
231                    ));
232                    commands.spawn((
233                        Mesh3d(meshes.choose(&mut material_rng).unwrap().0.clone()),
234                        MeshMaterial3d(materials.choose(&mut material_rng).unwrap().clone()),
235                        Transform::from_xyz(0.0, (x as f32) * scale, (y as f32) * scale),
236                    ));
237                }
238            }
239            // camera
240            let center = 0.5 * scale * Vec3::new(WIDTH as f32, HEIGHT as f32, WIDTH as f32);
241            commands.spawn((Camera3d::default(), Transform::from_translation(center)));
242            // Inside-out box around the meshes onto which shadows are cast (though you cannot see them...)
243            commands.spawn((
244                Mesh3d(mesh_assets.add(Cuboid::from_size(2.0 * 1.1 * center))),
245                MeshMaterial3d(material_assets.add(StandardMaterial::from(Color::WHITE))),
246                Transform::from_scale(-Vec3::ONE).with_translation(center),
247                NotShadowCaster,
248            ));
249        }
250    }
251
252    commands.spawn((
253        DirectionalLight {
254            shadows_enabled: args.shadows,
255            ..default()
256        },
257        Transform::IDENTITY.looking_at(Vec3::new(0.0, -1.0, -1.0), Vec3::Y),
258    ));
259}
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 86)
85fn remove(mut commands: Commands, cube_entity: Single<Entity, With<Cube>>) {
86    commands.entity(*cube_entity).remove::<Cube>();
87}
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 47)
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        && let Some(entity) = query.iter().next()
46    {
47        commands.entity(entity).remove::<MyComponent>();
48    }
49}
examples/ecs/component_hooks.rs (line 143)
136fn trigger_hooks(
137    mut commands: Commands,
138    keys: Res<ButtonInput<KeyCode>>,
139    index: Res<MyComponentIndex>,
140) {
141    for (key, entity) in index.iter() {
142        if !keys.pressed(*key) {
143            commands.entity(*entity).remove::<MyComponent>();
144        }
145    }
146    for key in keys.get_just_pressed() {
147        commands.spawn(MyComponent(*key));
148    }
149}
examples/window/screenshot.rs (line 38)
31fn screenshot_saving(
32    mut commands: Commands,
33    screenshot_saving: Query<Entity, With<Capturing>>,
34    window: Single<Entity, With<Window>>,
35) {
36    match screenshot_saving.iter().count() {
37        0 => {
38            commands.entity(*window).remove::<CursorIcon>();
39        }
40        x if x > 0 => {
41            commands
42                .entity(*window)
43                .insert(CursorIcon::from(SystemCursorIcon::Progress));
44        }
45        _ => {}
46    }
47}
examples/3d/depth_of_field.rs (line 170)
161fn update_dof_settings(
162    mut commands: Commands,
163    view_targets: Query<Entity, With<Camera>>,
164    app_settings: Res<AppSettings>,
165) {
166    let depth_of_field: Option<DepthOfField> = (*app_settings).into();
167    for view in view_targets.iter() {
168        match depth_of_field {
169            None => {
170                commands.entity(view).remove::<DepthOfField>();
171            }
172            Some(depth_of_field) => {
173                commands.entity(view).insert(depth_of_field);
174            }
175        }
176    }
177}
Source

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

Removes a Bundle of components from the entity if the predicate returns true.

This is useful for chaining method calls.

§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)
        .remove_if::<(Defense, CombatBundle)>(|| !player.is_spectator());
}
Source

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

Removes a Bundle of components from 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_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 401)
400    pub fn cleanup_menu(mut commands: Commands, menu_data: Res<MenuData>) {
401        commands.entity(menu_data.root_entity).despawn();
402    }
examples/stress_tests/many_buttons.rs (line 322)
321fn despawn_ui(mut commands: Commands, root_node: Single<Entity, (With<Node>, Without<ChildOf>)>) {
322    commands.entity(*root_node).despawn();
323}
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 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 queue_silenced<C, T, M>(&mut self, command: C) -> &mut EntityCommands<'a>

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

Unlike EntityCommands::queue_handled, this will completely ignore any errors that occur.

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 observe<E, B, M>( &mut self, observer: impl IntoObserverSystem<E, B, M>, ) -> &mut EntityCommands<'a>
where E: EntityEvent, B: Bundle,

Creates an Observer watching for an EntityEvent of type E whose EntityEvent::event_target targets this entity.

Examples found in repository?
examples/usage/context_menu.rs (lines 63-68)
60fn setup(mut commands: Commands) {
61    commands.spawn(Camera2d);
62
63    commands.spawn(background_and_button()).observe(
64        // any click bubbling up here should lead to closing any open menu
65        |_: On<Pointer<Press>>, mut commands: Commands| {
66            commands.trigger(CloseContextMenus);
67        },
68    );
69}
70
71fn on_trigger_close_menus(
72    _event: On<CloseContextMenus>,
73    mut commands: Commands,
74    menus: Query<Entity, With<ContextMenu>>,
75) {
76    for e in menus.iter() {
77        commands.entity(e).despawn();
78    }
79}
80
81fn on_trigger_menu(event: On<OpenContextMenu>, mut commands: Commands) {
82    commands.trigger(CloseContextMenus);
83
84    let pos = event.pos;
85
86    debug!("open context menu at: {pos}");
87
88    commands
89        .spawn((
90            Name::new("context menu"),
91            ContextMenu,
92            Node {
93                position_type: PositionType::Absolute,
94                left: px(pos.x),
95                top: px(pos.y),
96                flex_direction: FlexDirection::Column,
97                ..default()
98            },
99            BorderColor::all(Color::BLACK),
100            BorderRadius::all(px(4)),
101            BackgroundColor(Color::linear_rgb(0.1, 0.1, 0.1)),
102            children![
103                context_item("fuchsia", basic::FUCHSIA),
104                context_item("gray", basic::GRAY),
105                context_item("maroon", basic::MAROON),
106                context_item("purple", basic::PURPLE),
107                context_item("teal", basic::TEAL),
108            ],
109        ))
110        .observe(
111            |event: On<Pointer<Press>>,
112             menu_items: Query<&ContextMenuItem>,
113             mut clear_col: ResMut<ClearColor>,
114             mut commands: Commands| {
115                let target = event.original_event_target();
116
117                if let Ok(item) = menu_items.get(target) {
118                    clear_col.0 = item.0.into();
119                    commands.trigger(CloseContextMenus);
120                }
121            },
122        );
123}
More examples
Hide additional examples
examples/window/screenshot.rs (line 27)
17fn screenshot_on_spacebar(
18    mut commands: Commands,
19    input: Res<ButtonInput<KeyCode>>,
20    mut counter: Local<u32>,
21) {
22    if input.just_pressed(KeyCode::Space) {
23        let path = format!("./screenshot-{}.png", *counter);
24        *counter += 1;
25        commands
26            .spawn(Screenshot::primary_window())
27            .observe(save_to_disk(path));
28    }
29}
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/ecs/hotpatching_systems.rs (line 78)
57fn setup(mut commands: Commands) {
58    commands.spawn(Camera2d);
59
60    commands
61        .spawn((
62            Node {
63                width: percent(100),
64                height: percent(100),
65                align_items: AlignItems::Center,
66                justify_content: JustifyContent::Center,
67                flex_direction: FlexDirection::Column,
68                ..default()
69            },
70            children![(
71                Text::default(),
72                TextFont {
73                    font_size: 100.0,
74                    ..default()
75                },
76            )],
77        ))
78        .observe(on_click);
79}
examples/3d/mixed_lighting.rs (lines 174-181)
166fn spawn_scene(commands: &mut Commands, asset_server: &AssetServer) {
167    commands
168        .spawn(SceneRoot(
169            asset_server.load(
170                GltfAssetLabel::Scene(0)
171                    .from_asset("models/MixedLightingExample/MixedLightingExample.gltf"),
172            ),
173        ))
174        .observe(
175            |_: On<SceneInstanceReady>,
176             mut lighting_mode_changed_writer: MessageWriter<LightingModeChanged>| {
177                // When the scene loads, send a `LightingModeChanged` event so
178                // that we set up the lightmaps.
179                lighting_mode_changed_writer.write(LightingModeChanged);
180            },
181        );
182}
examples/animation/morph_targets.rs (line 45)
28fn setup(
29    mut commands: Commands,
30    asset_server: Res<AssetServer>,
31    mut graphs: ResMut<Assets<AnimationGraph>>,
32) {
33    let (graph, index) = AnimationGraph::from_clip(
34        asset_server.load(GltfAssetLabel::Animation(2).from_asset(GLTF_PATH)),
35    );
36
37    commands
38        .spawn((
39            AnimationToPlay {
40                graph_handle: graphs.add(graph),
41                index,
42            },
43            SceneRoot(asset_server.load(GltfAssetLabel::Scene(0).from_asset(GLTF_PATH))),
44        ))
45        .observe(play_animation_when_ready);
46
47    commands.spawn((
48        DirectionalLight::default(),
49        Transform::from_rotation(Quat::from_rotation_z(PI / 2.0)),
50    ));
51
52    commands.spawn((
53        Camera3d::default(),
54        Transform::from_xyz(3.0, 2.1, 10.2).looking_at(Vec3::ZERO, Vec3::Y),
55    ));
56}
Source

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

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

The other entity will receive all the components of the original that implement Clone or Reflect except those that are denied in the config.

§Panics

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

§Example

Configure through EntityClonerBuilder<OptOut> 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 ComponentA but not ComponentB onto the target.
    entity.clone_with_opt_out(target, |builder| {
        builder.deny::<ComponentB>();
    });
}

See EntityClonerBuilder for more options.

Source

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

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

The other entity will receive only the components of the original that implement Clone or Reflect and are allowed in the config.

§Panics

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

§Example

Configure through EntityClonerBuilder<OptIn> 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 ComponentA but not ComponentB onto the target.
    entity.clone_with_opt_in(target, |builder| {
        builder.allow::<ComponentA>();
    });
}

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_opt_out/ opt_out.

§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 entity.
    let mut entity_clone = entity.clone_and_spawn();
}
Source

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

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

The clone will receive all the components of the original that implement Clone or Reflect except those that are denied in the config.

See the methods on EntityClonerBuilder<OptOut> 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 entity with ComponentA but without ComponentB.
    let mut entity_clone = entity.clone_and_spawn_with_opt_out(|builder| {
        builder.deny::<ComponentB>();
    });
}
Source

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

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

The clone will receive only the components of the original that implement Clone or Reflect and are allowed in the config.

See the methods on EntityClonerBuilder<OptIn> 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 entity with ComponentA but without ComponentB.
    let mut entity_clone = entity.clone_and_spawn_with_opt_in(|builder| {
        builder.allow::<ComponentA>();
    });
}
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,

Moves the specified components of this entity into another entity.

Components with Ignore clone behavior will not be moved, while components that have a Custom clone behavior will be cloned using it and then removed from the source entity. All other components will be moved without any other special handling.

Note that this will trigger on_remove hooks/observers on this entity and on_insert/on_add hooks/observers on the target entity.

§Panics

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

Source

pub fn trigger<'t, E>( &mut self, event_fn: impl FnOnce(Entity) -> E, ) -> &mut EntityCommands<'a>
where E: EntityEvent, <E as Event>::Trigger<'t>: Default,

Passes the current entity into the given function, and triggers the EntityEvent returned by that function.

§Example

A surprising number of functions meet the trait bounds for event_fn:


#[derive(EntityEvent)]
struct Explode(Entity);

impl From<Entity> for Explode {
   fn from(entity: Entity) -> Self {
      Explode(entity)
   }
}


fn trigger_via_constructor(mut commands: Commands) {
    // The fact that `Epxlode` is a single-field tuple struct
    // ensures that `Explode(entity)` is a function that generates
    // an EntityEvent, meeting the trait bounds for `event_fn`.
    commands.spawn_empty().trigger(Explode);

}


fn trigger_via_from_trait(mut commands: Commands) {
    // This variant also works for events like `struct Explode { entity: Entity }`
    commands.spawn_empty().trigger(Explode::from);
}

fn trigger_via_closure(mut commands: Commands) {
    commands.spawn_empty().trigger(|entity| Explode(entity));
}

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 path 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 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, W> HasTypeWitness<W> for T
where W: MakeTypeWitness<Arg = T>, T: ?Sized,

Source§

const WITNESS: W = W::MAKE

A constant of the type witness
Source§

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

Source§

const TYPE_EQ: TypeEq<T, <T as Identity>::Type> = TypeEq::NEW

Proof that Self is the same type as Self::Type, provides methods for casting between Self and Self::Type.
Source§

type Type = T

The same type as Self, used to emulate type equality bounds (T == U) with associated type equality constraints (T: Identity<Type = U>).
Source§

impl<T> InitializeFromFunction<T> for T

Source§

fn initialize_from_function(f: fn() -> T) -> T

Create an instance of this type from an initialization function
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<T> IntoResult<T> for T

Source§

fn into_result(self) -> Result<T, RunSystemError>

Converts this type into the system output type.
Source§

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

Source§

fn into_sample(self) -> T

Source§

impl<A> Is for A
where A: Any,

Source§

fn is<T>() -> bool
where T: Any,

Checks if the current type “is” another type, using a TypeId equality comparison. This is most useful in the context of generic logic. Read more
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> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<Ret> SpawnIfAsync<(), Ret> for Ret

Source§

fn spawn(self) -> Ret

Spawn the value into the dioxus runtime if it is an async block
Source§

impl<T, O> SuperFrom<T> for O
where O: From<T>,

Source§

fn super_from(input: T) -> O

Convert from a type to another type.
Source§

impl<T, O, M> SuperInto<O, M> for T
where O: SuperFrom<T, M>,

Source§

fn super_into(self) -> O

Convert from a type to another type.
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<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,