Claude Media
Claude CodeでBevyのRustゲームを開発する手順

Claude CodeでBevyのRustゲームを開発する手順

BevyでRustゲームを作る公式クイックスタートの手順と、Claude CodeのCargo権限・hooks設定によるビルド高速化をあわせて解説します。

BevyとはRust製のECSゲームエンジン

Bevyは、Rustだけで書かれたオープンソースのゲームエンジンです。ECS(Entity Component System)というデータ駆動の設計パターンを中核に据え、ゲームの状態を「エンティティ」「コンポーネント」「システム」の3つに分解して組み立てます。

エンジン本体を動かすだけならRustのインストールのみで完結します。ウィンドウ表示や音声・入力など環境固有の機能を使うときだけ、OS別の追加ライブラリが必要になります。Claude CodeはRustのコード生成・実行・デバッグを一通りこなせる汎用のコーディングエージェントです。Bevy専用の拡張を用意しなくても、cargoコマンドを介した通常のRust開発フローの延長でプロジェクトを進められます。

本記事は公式のQuick Start「Getting Started」の手順に沿って進めます。プロジェクト作成からECSの基礎、Claude Code側でビルドを速く回すための権限・hooks設定までを扱います。同じRustのプロジェクトでMCPサーバーを書く機会があるなら、RustでMCPサーバーを書く公式SDKの使い方も参考になります。

開発を始める前に整えるもの

Bevyを動かすには、最新の安定版Rustツールチェーンと、OS別の追加ライブラリが必要です。BevyのMSRV(サポートする最小Rustバージョン)は「最新の安定版リリース」と定義されているため、rustup updateで常に最新の状態を保つ必要があります。

rustc --version
cargo --version

OS別の追加ライブラリも必要です。LinuxならVulkan関連パッケージ、WindowsならVisual Studio C++ Build Toolsの「Desktop development with C++」ワークロード、macOSならXcodeのコマンドラインツール(xcode-select --install)を入れておきます。

コードエディタは、Language Server Protocolに対応しrust-analyzerを使えるものが公式に推奨されています。Claude Code自体はエディタと独立して動くターミナルベースのエージェントです。VS Codeなど別ウィンドウでrust-analyzerの補完を見ながら、Claude Codeに実装を指示するという組み合わせが機能します。Rustの言語自体に不慣れな場合は、公式が案内するThe Rust Book・Rust by Example・Rustlingsで基礎を先に固めておくと、Claude Codeが生成したコードの意図を追いやすくなります。

手順 — Bevyプロジェクトを作って動かす

ステップ1: Bevyをプロジェクトに追加する

最初のステップは、通常のRust実行プロジェクトを作り、依存関係にBevyを加えることです。cargo newで新規プロジェクトを作成し、cargo addでBevyを追加すれば準備は完了します。

cargo new my_bevy_game
cd my_bevy_game
cargo add bevy

Cargo.tomlにはbevy = "0.19"のように依存関係が追記され、editionには"2024"が指定されます。公式のGitHubリポジトリをクローンしてgit checkout v0.19.0のようにバージョンを切り替えれば、同梱の実例も試せます。cargo run --example breakoutのように実行するだけです。

ステップ2: ウィンドウを表示する

Bevyのプログラムは、すべてAppという1つの構造体を中心に組み立てます。最小のBevyアプリはApp::new().run()のわずか1行で動きますが、これだけでは何も起こりません。

use bevy::prelude::*;
 
fn main() {
    App::new().run();
}

Appはゲームのデータを保持するWorldと、ループを制御する仕組みを持つだけの「空の器」です。ウィンドウ表示やレンダリングといった機能は、DefaultPluginsというプラグイン群を追加して初めて有効になります。

App::new()
    .add_plugins(DefaultPlugins)
    .run();

DefaultPluginsを追加すると、2D/3Dレンダラー・アセット読み込み・UI・ウィンドウ・入力といった、一般的なゲームエンジンに期待される機能がまとめて有効になります。

ステップ3: コンポーネントとシステムを書く

Bevyのゲームロジックは、すべてECSというパターンで記述します。エンティティは一意の「モノ」、コンポーネントはエンティティに付けるデータ、システムは特定のコンポーネントを持つエンティティに対して実行するロジックです。

他のRust製ECS実装は複雑なライフタイムやトレイト、ビルダーパターンを要求しがちです。Bevy ECSはコンポーネントを#[derive(Component)]を付けた普通の構造体として、システムを普通のRust関数として書けます。

#[derive(Component)]
struct Person;
 
#[derive(Component)]
struct Name(String);
 
fn add_people(mut commands: Commands) {
    commands.spawn((Person, Name("Elaina Proctor".to_string())));
    commands.spawn((Person, Name("Renzo Hume".to_string())));
}

add_peopleは起動時に1度だけ実行する「startup system」として登録します。エンティティを取得して処理するにはQueryを使います。

fn greet_people(query: Query<&Name, With<Person>>) {
    for name in &query {
        println!("hello {}!", name.0);
    }
}
 
fn main() {
    App::new()
        .add_plugins(DefaultPlugins)
        .add_systems(Startup, add_people)
        .add_systems(Update, greet_people)
        .run();
}

値を書き換えるシステムはQueryを可変にし、&mutで取得したコンポーネントを直接更新します。複数のシステムを決まった順序で実行したいときは.chain()を使います。

fn update_people(mut query: Query<&mut Name, With<Person>>) {
    for mut name in &mut query {
        if name.0 == "Elaina Proctor" {
            name.0 = "Elaina Hume".to_string();
        }
    }
}

update_peopleのあとにgreet_peopleを実行するよう.chain()で順序を固定すれば、名前を変更してから挨拶する、という依存関係を保証できます。デフォルトではシステムは可能な限り並列実行されるため、順序を保証したい処理だけを明示的に連結します。

ステップ4: PluginとResourceで整理する

Bevyのもう1つの中核原則がモジュール性です。レンダラーのような内蔵機能も自作のゲームロジックも、すべてPluginとして実装します。Pluginトレイトを実装した構造体をadd_pluginsで登録すれば、複数のシステムをひとまとまりにできます。

pub struct HelloPlugin;
 
impl Plugin for HelloPlugin {
    fn build(&self, app: &mut App) {
        app.add_systems(Startup, add_people);
        app.add_systems(Update, (update_people, greet_people).chain());
    }
}

エンティティやコンポーネントに紐づかない「グローバルに1つだけ」のデータはResourceトレイトで表現します。経過時間・アセットコレクション・レンダラーなどが典型例です。挨拶を2秒おきに1回へ間引くなら、Timer型のリソースを使います。

#[derive(Resource)]
struct GreetTimer(Timer);
 
fn greet_people(
    time: Res<Time>,
    mut timer: ResMut<GreetTimer>,
    query: Query<&Name, With<Person>>,
) {
    if timer.0.tick(time.delta()).just_finished() {
        for name in &query {
            println!("hello {}!", name.0);
        }
    }
}

insert_resourceでリソースの初期値をプラグインに登録すれば、以降はどのシステムからでもResResMut経由でアクセスできます。

Claude Codeでビルドを速くする設定

Bevyは依存クレートが多く、素のデバッグビルドでは反復のたびに待ち時間が発生します。Claude Codeで開発するなら、確認プロンプトを減らす権限設定と、ビルド速度を上げるCargo設定の両方を先に整えておくと作業が滑らかになります。

Claude Codeは既定ではcargo runのようなBashコマンドの実行ごとに確認を求めます。頻繁に使うコマンドは.claude/settings.jsonpermissions.allowにワイルドカード付きで登録しておくと、確認なしで実行できます。

{
  "permissions": {
    "allow": [
      "Bash(cargo run *)",
      "Bash(cargo check *)",
      "Bash(cargo test *)"
    ]
  }
}

*はサブコマンドより後ろに置く必要があります。Bash(cargo *)と書くとcargoの全コマンドを確認なしで許可してしまうため、意図しないコマンドまで通ってしまう点には注意します。Bash権限ルールが複合コマンドをどう評価するかはClaude CodeのBash権限ルールは複合コマンドをどう評価するかにまとめています。登録済みルールの一覧管理はClaude Codeの/permissionsコマンドで権限ルールとauto mode拒否を管理するで扱っています。

ファイル編集のたびにcargo checkを自動実行したい場合は、PostToolUseフックを使います。

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "cargo check",
            "if": "Edit(*.rs)"
          }
        ]
      }
    ]
  }
}

ifフィールドは権限ルールと同じ構文でツール名と引数を照合するため、.rsファイルの編集時だけcargo checkを走らせる、という絞り込みができます。Hooksの全イベントと設定パターンはClaude Code Hooks完全ガイドにまとめています。

Cargo側でも、反復ビルドを速くする設定がいくつか公式に案内されています。

設定効果向き不向き
dynamic_linking機能効果再リンクを省略でき体感インパクトが最も大きい向き不向き◎。開発中は有効に、出荷前は無効化する
lld / moldリンカー効果リンク工程を高速化(moldは最大5倍)向き不向き○。OS別の追加インストールが必要
devプロファイルのopt-level調整効果依存クレートだけ最適化してデバッグ実行を軽くする向き不向き◎。ほぼ全プロジェクトで有効
Cranelift codegen効果LLVMよりコンパイルが速いがバイナリは最適化されない向き不向き△。nightly限定、macOSでは不具合報告がある

dynamic_linkingはcargo add bevy -F dynamic_linking、または--features bevy/dynamic_linking付きのcargo runで有効にできます。出荷用ビルドではlibbevy_dylibの同梱が必要になるため、無効化してから配布するのが基本です。

Cargo.tomlの最適化プロファイル例
[profile.dev]
opt-level = 1
 
[profile.dev.package."*"]
opt-level = 3

よくあるつまずき

公式のTroubleshootingページには、Bevy特有のエラーが3つ整理されています。

「Unable to find a GPU」というパニックは、Vulkan対応ドライバが入っていないか、GPUのないヘッドレス環境で実行したときに出ます。Linuxではvulkan-intelvulkan-radeonなどVulkan関連パッケージの導入で解消します。

Windowsで動的リンクビルドをVS Codeのデバッガから起動すると、終了コード-1073741515で落ちることがあります。原因はデバッグ拡張のパス解決の癖で、launch.jsonPATH環境変数にRustツールチェーンのディレクトリを追加すれば解決します。

Wasmターゲット向けにビルドすると、getrandomクレートのコンパイルエラーが出ることがあります。uuidなど複数の依存が別バージョンのgetrandomを要求している場合、package指定でクレート名を分けたうえでwasm_jsフィーチャーを個別に有効化する必要があります。

Claude Code側で気をつけたいのは、初回のcargo runがBevy本体を丸ごとコンパイルするため数分かかる点です。応答が返ってこないように見えても実際は処理中であることが多く、2回目以降のビルドは差分だけになるため体感速度は大きく変わります。

まとめ

Claude CodeでBevyのゲームを作る流れは、通常のRust開発と同じくcargo newcargo add bevyから始まります。ECSの基本(エンティティ・コンポーネント・システム)を押さえれば、PluginとResourceによるコードの整理まで、公式のGetting Startedがそのままチュートリアルとして機能します。

Claude Code側で効くのは、頻出コマンドをpermissions.allowに登録して確認プロンプトを減らすことと、PostToolUseフックで.rs編集のたびにcargo checkを回すことの2点です。dynamic_linking機能やlld・moldリンカーといったCargo側のビルド高速化と組み合わせれば、Rustの長いコンパイル時間もある程度は吸収できます。

この記事を共有:XはてブLinkedIn