佐藤のメモ帳

Rust, Python, Java, AWS, etc...

Rust Bevy Queryについて

はじめに

本記事はBevy非公式(と思えないほど素晴らしい)サイトのメモである。

bevy-cheatbook.github.io

メモ

BevyにおいてQueryとはEntityのComponentを指定した条件で取得し、アクセスする機能である。

fn check_zero_health(
    // `Health`と`Transform`Componentを持つEntityにアクセスする
    // `Health`は読み取り専用で取得し、`Transform`は変更可能(mut)で取得する
    // オプション: `Player`Componetが存在するなら取得する
    mut query: Query<(&Health, &mut Transform, Option<&Player>)>,
) {
    // 一致する全てのEntityを取得する
    for (health, mut transform, player) in query.iter_mut() {
        eprintln!("Entity at {} has {} HP.", transform.translation, health.hp);

        // HPが0なら、中央に移動
        if health.hp <= 0.0 {
            transform.translation = Vec3::ZERO;
        }

        if let Some(player) = player {
            // ここではEntityは`Player`
        }
    }
}

Entityから特定のComponentを取得する例

if let Ok((health, mut transform)) = query.get_mut(entity) {
    // Componentに対する何らかの操作
} else {
    // Entityは指定したComponentを持っていない
}

EntityのIDを取得する例

// `Query`に`Entity`を追加し、EntitiyのIDを取得する
fn query_entities(q: Query<(Entity, /* ... */)>) {
    for (e, /* ... */) in q.iter() {
        // `e` はEntityのID
    }
}

QueryでEntityを1つに特定できる場合は、single/single_mutで取得することができる。 上の例のようにループする必要はない。

fn query_player(mut q: Query<(&Player, &mut Transform)>) {
    let (player, mut transform) = q.single_mut()
        .expect("There should always be exactly one player in the game!");
}

注意

QueryはComponentに対して機能する。Bundleを使用して Entityを作成している場合、そのBundleから特定のComponentをQueryで参照する必要がある。

Query Filters

Query Filterを使用して、QueryするEntityを絞り込むことができる。 特定のComponentを持つEntityを取得する場合はWith/Withoutを使用する。

fn debug_player_hp(
    // Enemyを除くPlayerのHealthを取得する(オプションとして名前も取得する)
    query: Query<(&Health, Option<&PlayerName>), (With<Player>, Without<Enemy>)>,
) {
    for (health, name) in query.iter() {
        if let Some(name) = name {
            eprintln!("Player {} has {} HP.", name.0, health.hp);
        } else {
            eprintln!("Unknown player has {} HP.", health.hp);
        }
    }
}