bevy/examples/ecs/generic_system.rs
Carter Anderson cd15f0f5be Accept Bundles for insert and remove. Deprecate insert/remove_bundle (#6039)
# Objective

Take advantage of the "impl Bundle for Component" changes in #2975 / add the follow up changes discussed there.

## Solution

- Change `insert` and `remove` to accept a Bundle instead of a Component (for both Commands and World)
- Deprecate `insert_bundle`, `remove_bundle`, and `remove_bundle_intersection`
- Add `remove_intersection`

---

## Changelog

- Change `insert` and `remove` now accept a Bundle instead of a Component (for both Commands and World)
- `insert_bundle` and `remove_bundle` are deprecated
 

## Migration Guide

Replace `insert_bundle` with `insert`:
```rust
// Old (0.8)
commands.spawn().insert_bundle(SomeBundle::default());
// New (0.9)
commands.spawn().insert(SomeBundle::default());
```

Replace `remove_bundle` with `remove`:
```rust
// Old (0.8)
commands.entity(some_entity).remove_bundle::<SomeBundle>();
// New (0.9)
commands.entity(some_entity).remove::<SomeBundle>();
```

Replace `remove_bundle_intersection` with `remove_intersection`:
```rust
// Old (0.8)
world.entity_mut(some_entity).remove_bundle_intersection::<SomeBundle>();
// New (0.9)
world.entity_mut(some_entity).remove_intersection::<SomeBundle>();
```

Consider consolidating as many operations as possible to improve ergonomics and cut down on archetype moves:
```rust
// Old (0.8)
commands.spawn()
  .insert_bundle(SomeBundle::default())
  .insert(SomeComponent);

// New (0.9) - Option 1
commands.spawn().insert((
  SomeBundle::default(),
  SomeComponent,
))

// New (0.9) - Option 2
commands.spawn_bundle((
  SomeBundle::default(),
  SomeComponent,
))
```

## Next Steps

Consider changing `spawn` to accept a bundle and deprecate `spawn_bundle`.
2022-09-21 21:47:53 +00:00

89 lines
2.9 KiB
Rust

//! Generic types allow us to reuse logic across many related systems,
//! allowing us to specialize our function's behavior based on which type (or types) are passed in.
//!
//! This is commonly useful for working on related components or resources,
//! where we want to have unique types for querying purposes but want them all to work the same way.
//! This is particularly powerful when combined with user-defined traits to add more functionality to these related types.
//! Remember to insert a specialized copy of the system into the schedule for each type that you want to operate on!
//!
//! For more advice on working with generic types in Rust, check out <https://doc.rust-lang.org/book/ch10-01-syntax.html>
//! or <https://doc.rust-lang.org/rust-by-example/generics.html>
use bevy::prelude::*;
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
enum AppState {
MainMenu,
InGame,
}
#[derive(Component)]
struct TextToPrint(String);
#[derive(Component, Deref, DerefMut)]
struct PrinterTick(Timer);
#[derive(Component)]
struct MenuClose;
#[derive(Component)]
struct LevelUnload;
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_state(AppState::MainMenu)
.add_startup_system(setup_system)
.add_system(print_text_system)
.add_system_set(
SystemSet::on_update(AppState::MainMenu).with_system(transition_to_in_game_system),
)
// add the cleanup systems
.add_system_set(
// Pass in the types your system should operate on using the ::<T> (turbofish) syntax
SystemSet::on_exit(AppState::MainMenu).with_system(cleanup_system::<MenuClose>),
)
.add_system_set(
SystemSet::on_exit(AppState::InGame).with_system(cleanup_system::<LevelUnload>),
)
.run();
}
fn setup_system(mut commands: Commands) {
commands.spawn_bundle((
PrinterTick(Timer::from_seconds(1.0, true)),
TextToPrint("I will print until you press space.".to_string()),
MenuClose,
));
commands.spawn_bundle((
PrinterTick(Timer::from_seconds(1.0, true)),
TextToPrint("I will always print".to_string()),
LevelUnload,
));
}
fn print_text_system(time: Res<Time>, mut query: Query<(&mut PrinterTick, &TextToPrint)>) {
for (mut timer, text) in &mut query {
if timer.tick(time.delta()).just_finished() {
info!("{}", text.0);
}
}
}
fn transition_to_in_game_system(
mut state: ResMut<State<AppState>>,
keyboard_input: Res<Input<KeyCode>>,
) {
if keyboard_input.pressed(KeyCode::Space) {
state.set(AppState::InGame).unwrap();
}
}
// Type arguments on functions come after the function name, but before ordinary arguments.
// Here, the `Component` trait is a trait bound on T, our generic type
fn cleanup_system<T: Component>(mut commands: Commands, query: Query<Entity, With<T>>) {
for e in &query {
commands.entity(e).despawn_recursive();
}
}