0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Rust×Bevyゲーム開発レシピ: シーンを切り替えよう

Last updated at Posted at 2025-08-20

Bevyを使った個人ゲーム開発を行なっている登尾(のぼりお)です。今回はBevyでのシーン切り替えを解説します。

例えばPhaser.jsなどでゲーム開発の経験があるとシーンごとの管理を特定のクラスに閉じ込め、切り替え自体も、エンジン側でやってくれます。
そういった経験からBevyに移行すると、シーン切り替えの方法に戸惑ってしまうかもしれません。
というのも、BevyはECS(Entity Component System)というデータ駆動なゲームエンジンなので、そうでないモデルのゲームエンジンの経験と考え方が異なるためです。

ECSについて詳しくは解説しませんが、シーンを切り替えるという文脈において以下の考え方を持つとシーンを切り替えるという実装が可能になります。

今回は4つのステップで解説していきます。

1) どのシーンかを表す状態

例えば、タイトル画面、プレイ中の画面という2つのシーンがあると考えた時以下のようにStateを定義します。

use bevy::prelude::*;

#[derive(States, Debug, Clone, Eq, PartialEq, Hash, Default)]
enum SceneState {
    #[default]
    Title,
    Play,
}

2) init_stateでSceneStateを設定

SceneStateをBevyのAppにinit_stateによって設定します。

fn main() {
    App::new()
        .add_plugins(DefaultPlugins)
        .init_state::<SceneState>()
        .run();
}

これによってBevyのアプリ内において今どのStateSceneなのか、StateSceneを切り替える、という二つの機能が呼べるようになります。(その呼び出し方は後述。)

SceneStateには、#[default]のアトリビュートによってTitleがデフォルトであると指定しているため、StateSceneを取り出すとTitleが返ってきます。

3) シーンが切り替わった時にだけ実行されるシステム

Appへadd_systemsする書き方は、前回の記事で以下のような例を書きました。

fn main() {
    App::new()
        .add_plugins(DefaultPlugins)
        .add_systems(Startup, setup_clear_color)
        .add_systems(Update, change_clear_color)
        .run();
}

上記は、一度だけ(Startup)あるいは、常に(Update)の場合ですが、先ほどinit_stateで設定した SceneStateがどの値に切り替わったか という条件の時だけ、実行できるシステムを書くことができます。

fn main() {
    App::new()
        .add_plugins(DefaultPlugins)
        .init_state::<SceneState>()
        .add_systems(OnEnter(SceneState::Title), enter_title)
        .add_systems(OnEnter(SceneState::Play), enter_play)
        .run();
}

このようにOnEnterの中にStateを渡すと、その状態に変わった時のみ呼び出される関数を定義できます。

  • enter_title関数: ゲーム開始時に呼ばれる(SceneStateはTitleなので)、あるいは再度SceneStateがTitleに切り替わった時
  • enter_play関数: SceneStateがPlayに切り替わった時

実際に切り替わった時のenter_title関数、enter_play関数はシンプルに背景が変わるだけの例ですが、以下の通りです。

fn enter_title(mut clear: ResMut<ClearColor>) {
    clear.0 = Color::srgb(0.5, 0.0, 0.0)
}

fn enter_play(mut clear: ResMut<ClearColor>) {
    clear.0 = Color::srgb(0.0, 0.0, 0.5)
}

4) 実際のシーン切り替え

さて、最後に上記までのコードを実行しても、最初のTitleシーンのままなので、TitleからPlay、PlayからTitleに切り替えてみましょう。

スペースキーを押すと交互に切り替える関数は以下のとおりです。

fn toggle_scene_on_space(
    keys: Res<ButtonInput<KeyCode>>,
    state: Res<State<SceneState>>,
    mut next: ResMut<NextState<SceneState>>,
) {
    if keys.just_pressed(KeyCode::Space) {
        match *state.get() {
            SceneState::Title => next.set(SceneState::Play),
            SceneState::Play => next.set(SceneState::Title),
        }
    }
}

今がどのシーンかはstateで分かり、切り替える場合にはnextを使うというのが直感的に理解していただけると思います。

ここまでのコードによってスペースキーを押すと色が変わることでシーンが切り替わる様子を観察できます。

スクリーンショット 2025-08-20 16.55.36.png

スクリーンショット 2025-08-20 16.56.30.png

おしまい

今回のコードは以下の個人リポジトリで公開しています。

cloneした後に、

% cargo run --example scnes 

で挙動を起動できますので、そちらも参考にしてみてください。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?