B0001

为了保持 Rust 中关于引用规则(在一个组件上可以有一个可变引用或多个不可变引用),在同一个系统中,如果两个查询都请求对同一个组件进行可变访问,则无法实现。

错误代码示例

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_systems(Update, move_enemies_to_player)
        .run();
}

这将导致崩溃,因为无法同时在 `Transform` 上进行可变查询和不可变查询。

你有两种解决方法

解决方案 #1:使用 Without 进行不相交查询

由于一个 `Player` 实体不会同时是一个 `Enemy`,这两个查询实际上永远不会针对同一个实体。这可以通过 Without 在查询过滤器中进行编码。

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_systems(Update, move_enemies_to_player)
        .run();
}

解决方案 #2:使用 `ParamSet`

使用 `ParamSet` 可以将冲突的查询作为参数传入,但仍然需要你自己负责不要在系统中同时使用它们。

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_systems(Update, move_enemies_to_player)
        .run();
}