EP.06 は (Rust 製ゲームエンジン) × 。前 5 EP のエンジンと比べると独特ですが、Rust の型安全性と の関数型設計 が 生成と相性抜群です。 の hallucination をコンパイラが弾く 「二人三脚」 を体験する EP。 / Cursor との組合せが特に効きます。
1. Bevy の哲学
- ECS (Entity Component System) ファースト: OOP の継承を使わず、データとロジックを分離
- Data-Oriented Design: キャッシュ局所性を意識したメモリレイアウト
- Rust の所有権モデル: メモリ安全・データ競合フリー
- プラグインアーキテクチャ: 全機能が plugin、必要なものだけ組み合わせる
- Hot Reload (一部): 開発時のフィードバックループを高速化中
2. プロジェクトのセットアップ
# Rust ツールチェインがなければcurl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
# 新規プロジェクトcargo new my_bevy_gamecd my_bevy_game
# Cargo.toml に Bevy 追加# [dependencies]# bevy = "0.14"
cargo build # 初回は依存解決で 5-10 分
# 開発時の高速ビルド (dynamic linking)# [features]# default = ["bevy/dynamic_linking"]3. Hello, Bevy
use bevy::prelude::*;
fn main() { App::new() .add_plugins(DefaultPlugins) .add_systems(Startup, setup) .add_systems(Update, rotate_cube) .run();}
#[derive(Component)]struct RotatingCube;
fn setup( mut commands: Commands, mut meshes: ResMut<Assets<Mesh>>, mut materials: ResMut<Assets<StandardMaterial>>,) { // カメラ commands.spawn(Camera3dBundle { transform: Transform::from_xyz(0.0, 2.0, 5.0).looking_at(Vec3::ZERO, Vec3::Y), ..default() }); // ライト commands.spawn(PointLightBundle { point_light: PointLight { intensity: 1500.0, shadows_enabled: true, ..default() }, transform: Transform::from_xyz(4.0, 8.0, 4.0), ..default() }); // キューブ commands.spawn(( PbrBundle { mesh: meshes.add(Cuboid::default()), material: materials.add(Color::srgb(0.3, 0.8, 0.3)), ..default() }, RotatingCube, ));}
fn rotate_cube(time: Res<Time>, mut query: Query<&mut Transform, With<RotatingCube>>) { for mut transform in &mut query { transform.rotate_y(time.delta_seconds() * 1.0); }}4. ECS の三要素
| 要素 | Bevy での書き方 | 役割 |
|---|---|---|
| Entity | Commands::spawn() が返す Entity ID | ゲームオブジェクトの ID |
| Component | `#[derive(Component)] struct Health(f32)` | Entity に紐付くデータ |
| System | `fn damage_system(query: Query<&mut Health>)` | Entity 群を処理する関数 |
| Resource | `#[derive(Resource)] struct Score(u32)` | グローバル単一データ |
| Event | `#[derive(Event)] struct ScoredEvent(u32)` | System 間のメッセージ |
5. LLM が書きやすい System の例
use bevy::prelude::*;
#[derive(Component)]struct Player;
#[derive(Component)]struct Enemy;
#[derive(Component)]struct Velocity(Vec2);
#[derive(Resource, Default)]struct GameState { game_over: bool,}
// System 1: プレイヤー入力で速度更新fn handle_input( keys: Res<ButtonInput<KeyCode>>, mut query: Query<&mut Velocity, With<Player>>,) { let speed = 200.0; for mut vel in &mut query { vel.0 = Vec2::ZERO; if keys.pressed(KeyCode::ArrowLeft) { vel.0.x = -speed; } if keys.pressed(KeyCode::ArrowRight) { vel.0.x = speed; } if keys.pressed(KeyCode::ArrowUp) { vel.0.y = speed; } if keys.pressed(KeyCode::ArrowDown) { vel.0.y = -speed; } }}
// System 2: 速度に応じて位置更新fn apply_velocity(time: Res<Time>, mut query: Query<(&mut Transform, &Velocity)>) { for (mut transform, vel) in &mut query { transform.translation.x += vel.0.x * time.delta_seconds(); transform.translation.y += vel.0.y * time.delta_seconds(); }}
// System 3: プレイヤーと敵の衝突検出fn check_collisions( player_query: Query<&Transform, With<Player>>, enemy_query: Query<&Transform, With<Enemy>>, mut game_state: ResMut<GameState>,) { for player in &player_query { for enemy in &enemy_query { let dist = player.translation.distance(enemy.translation); if dist < 30.0 { game_state.game_over = true; } } }}6. Rust 型安全性 × LLM の二人三脚
- 1Claude に Rust コードを書かせる
- 2`cargo check` で型エラーが出る (Bevy の SystemParam 制約違反など)
- 3エラーメッセージを Claude に貼る
- 4Claude が修正案を返す (大抵 2-3 往復で通る)
- 5コンパイルが通れば、メモリ安全 + データ競合フリー + 期待した型で動くことが保証される
Python/GDScript で LLM が書いたコードは「動いたけど null 参照で死ぬ」 が起きやすい。Rust + Bevy では `Option<T>` / `Result<T, E>` が強制されるので、null 系のランタイムエラーがほぼ存在しない。ゲームを長時間プレイテストする心理的負担が劇的に下がる。
7. Bevy のバージョン差異への対処
- Cargo.toml を Claude に毎回見せる: Bevy のバージョンを明確化
- docs.rs の該当バージョン URL も貼る: docs.rs/bevy/0.14.0
- migration guide を併用: bevyengine.org/learn/migration-guides/
- `cargo doc --open` でローカル ドキュメント生成: バージョン整合性が確実
8. Bevy エコシステム
| カテゴリ | クレート | 用途 |
|---|---|---|
| 物理 | `bevy_rapier2d/3d`, `avian2d/3d` | 物理シミュレーション |
| UI | `bevy_egui`, `bevy_lunex` | デバッグ UI / ゲーム UI |
| Asset | `bevy_asset_loader` | アセット非同期読込 |
| Audio | `bevy_audio` (内蔵), `bevy_kira_audio` | 音声再生 |
| Editor | `bevy_editor_pls`, `bevy_inspector_egui` | ランタイム inspector |
| Tilemap | `bevy_ecs_tilemap` | 2D タイルマップ |
9. WebAssembly ターゲット
# WASM ビルドツールcargo install wasm-bindgen-clirustup target add wasm32-unknown-unknown
# ビルドcargo build --release --target wasm32-unknown-unknownwasm-bindgen --no-typescript --target web \ --out-dir ./out/ --out-name "my_bevy_game" \ ./target/wasm32-unknown-unknown/release/my_bevy_game.wasm
# 配信用 HTML を out/ に置いて、任意の Web サーバから配信# itch.io や Vercel 等にデプロイ可能10. 次の話
EP.07 は アセット生成統合 ── Stable Diffusion / Meshy / Suno / ElevenLabs をゲーム開発フローに組込むパターン。コード生成だけでなくアセット生成も LLM/生成 AI で完結させる流れ。
この記事の感想を教えてください
あなたの 1 クリックで、本当にこの記事は更新されます。「もっと詳しく」「続編希望」が一定数集まった記事は、 ふくふくが 実際に内容を拡充したり続編記事を公開 します。 送信したリアクションはお使いのブラウザに記録され、再カウントされません。