bevy/errors/B0001.md
bilsen 63fee2572b ParamSet for conflicting SystemParam:s (#2765)
# Objective
Add a system parameter `ParamSet` to be used as container for conflicting parameters.

## Solution
Added two methods to the SystemParamState trait, which gives the access used by the parameter. Did the implementation. Added some convenience methods to FilteredAccessSet. Changed `get_conflicts` to return every conflicting component instead of breaking on the first conflicting `FilteredAccess`.


Co-authored-by: bilsen <40690317+bilsen@users.noreply.github.com>
2022-03-29 23:39:38 +00:00

91 lines
2.2 KiB
Markdown

# B0001
To keep [Rust rules on references](https://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html#the-rules-of-references) (either one mutable reference or any number of immutable references) on a component, it is not possible to have two queries on the same component when one request mutable access to it in the same system.
Erroneous code example:
```rust,should_panic
use bevy::prelude::*;
#[derive(Component)]
struct Player;
#[derive(Component)]
struct Enemy;
fn move_enemies_to_player(
mut enemies: Query<&mut Transform, With<Enemy>>,
player: Query<&Transform, With<Player>>,
) {
// ...
}
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_system(move_enemies_to_player)
.run();
}
```
This will panic, as it's not possible to have both a mutable and an immutable query on `Transform` at the same time.
You have two solutions:
Solution #1: use disjoint queries using [`Without`](https://docs.rs/bevy/*/bevy/ecs/query/struct.Without.html)
As a `Player` entity won't be an `Enemy` at the same time, those two queries will acutally never target the same entity. This can be encoded in the query filter with [`Without`](https://docs.rs/bevy/*/bevy/ecs/query/struct.Without.html):
```rust,no_run
use bevy::prelude::*;
#[derive(Component)]
struct Player;
#[derive(Component)]
struct Enemy;
fn move_enemies_to_player(
mut enemies: Query<&mut Transform, With<Enemy>>,
player: Query<&Transform, (With<Player>, Without<Enemy>)>,
) {
// ...
}
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_system(move_enemies_to_player)
.run();
}
```
Solution #2: use a `ParamSet`
A `ParamSet` will let you have conflicting queries as a parameter, but you will still be responsible of not using them at the same time in your system.
```rust,no_run
use bevy::prelude::*;
#[derive(Component)]
struct Player;
#[derive(Component)]
struct Enemy;
fn move_enemies_to_player(
mut transforms: ParamSet<(
Query<&mut Transform, With<Enemy>>,
Query<&Transform, With<Player>>,
)>,
) {
// ...
}
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_system(move_enemies_to_player)
.run();
}
```