Bevy Version: | 0.14 | (current) |
---|
Commands
Relevant official examples:
ecs_guide
.
Use Commands
to spawn/despawn entities, add/remove components on existing
entities, manage resources, from your systems.
fn spawn_things(
mut commands: Commands,
) {
// manage resources
commands.insert_resource(MyResource::new());
commands.remove_resource::<MyResource>();
// create a new entity using `spawn`,
// providing the data for the components it should have
// (typically using a Bundle)
commands.spawn(PlayerBundle {
name: PlayerName("Henry".into()),
xp: PlayerXp(1000),
health: Health {
hp: 100.0, extra: 20.0
},
_p: Player,
sprite: Default::default(),
});
// you can use a tuple if you need additional components or bundles
// (tuples of component and bundle types are considered bundles)
// (note the extra parentheses)
let my_entity_id = commands.spawn((
// add some components
ComponentA,
ComponentB::default(),
// add some bundles
MyBundle::default(),
TransformBundle::default(),
)).id(); // get the Entity (id) by calling `.id()` at the end
// add/remove components of an existing entity
commands.entity(my_entity_id)
.insert(ComponentC::default())
.remove::<ComponentA>()
.remove::<(ComponentB, MyBundle)>();
// remove everything except the given components / bundles
commands.entity(my_entity_id)
.retain::<(TransformBundle, ComponentC)>();
}
fn make_all_players_hostile(
mut commands: Commands,
// we need the Entity id, to perform commands on specific entities
query: Query<Entity, With<Player>>,
) {
for entity in query.iter() {
commands.entity(entity)
// add an `Enemy` component to the entity
.insert(Enemy)
// remove the `Friendly` component
.remove::<Friendly>();
}
}
fn despawn_all_enemies(
mut commands: Commands,
query: Query<Entity, With<Enemy>>,
) {
for entity in query.iter() {
commands.entity(entity).despawn();
}
}
When do these actions get applied?
Commands
do not take effect immediately, because it wouldn't be safe to
modify the data layout in memory when other systems could be
running in parallel. When you do anything using Commands
, it gets queued to
be applied later when it is safe to do so.
Within the same schedule, you can add .before()
/.after()
ordering constraints to your systems, and Bevy will
automatically make sure that Commands get applied in-between if necessary, so
that the second system can see the changes made by the first system.
app.add_systems(Update, spawn_new_enemies_if_needed);
// This system will see any newly-spawned enemies when it runs,
// because Bevy will make sure to apply the first system's Commands
// (thanks to the explicit `.after()` dependency)
app.add_systems(Update, enemy_ai.after(spawn_new_enemies_if_needed));
If you do not have explicit ordering dependencies, it is undefined when Commands will be applied. It is possible that some systems will only see the changes on the next frame update!
Otherwise, Commands are normally applied at the end of every
schedule. Systems that live in different schedules
will see the changes. For example, Bevy's engine systems (that live in
PostUpdate
) will see the entities you spawn in your systems (that live in
Update
).
Custom Commands
Commands can also serve as a convenient way to do any custom manipulations
that require full access to the ECS World
. You can queue up
any custom code to run in a deferred fashion, the same way as the standard
commands work.
For a one-off thing, you can just pass a closure:
fn my_system(mut commands: Commands) {
let x = 420;
commands.add(move |world: &mut World| {
// do whatever you want with `world` here
// note: it's a closure, you can use variables from
// the parent scope/function
eprintln!("{}", x);
});
}
If you want something reusable, consider one-shot systems. They are a way to write regular Bevy systems and run them on-demand.
Extending the Commands API
If you want something more integrated, that feels like as if it was part of Bevy's Commands API, here is how to do it.
Create a custom type and implement the Command
trait:
use bevy::ecs::world::Command;
struct MyCustomCommand {
// you can have some parameters
data: u32,
}
impl Command for MyCustomCommand {
fn apply(self, world: &mut World) {
// do whatever you want with `world` and `self.data` here
}
}
// use it like this
fn my_other_system(mut commands: Commands) {
commands.add(MyCustomCommand {
data: 920, // set your value
});
}
And if you want to make it extra nice to use, you can create
an extension trait to add extra methods to Commands
:
pub trait MyCustomCommandsExt {
// define a method that we will be able to call on `commands`
fn do_custom_thing(&mut self, data: u32);
}
// implement our trait for Bevy's `Commands`
impl<'w, 's> MyCustomCommandsExt for Commands<'w, 's> {
fn do_custom_thing(&mut self, data: u32) {
self.add(MyCustomCommand {
data,
});
}
}
fn my_fancy_system(mut commands: Commands) {
// now we can call our custom method just like Bevy's `spawn`, etc.
commands.do_custom_thing(42);
}
Note: if you want to use your custom extension method from other Rust files, you will have to import your trait, or it will not be available:
use crate::thing::MyCustomCommandsExt;