diff --git a/docs/02_spec_design/PROJECT_EVALUATION_CANDID.md b/docs/02_spec_design/PROJECT_EVALUATION_CANDID.md new file mode 100644 index 0000000..2c0d0b0 --- /dev/null +++ b/docs/02_spec_design/PROJECT_EVALUATION_CANDID.md @@ -0,0 +1,126 @@ +# プロジェクト評価(忖度なし版) + +**対象**: Elixir × Rust ゲームエンジン(Vampire Survivor / MiniShooter) +**評価日**: 2026-02-25 +**目的**: 気持ちの良い総括ではなく、次の意思決定に使うための現実的評価 + +--- + +## 結論(先に要点) + +このプロジェクトは「技術的に面白いデモ」段階は超えており、実装密度も高い。 +ただし、現状のまま機能追加を続けると、**デバッグ難易度**と**保守コスト**が先に限界を迎える可能性が高い。 + +一言で言うと: + +> **方向性は正しい。だが、拡張前に土台の保守性を上げないと失速する。** + +--- + +## 1. 良い評価(事実として強い点) + +### 1.1 設計方針がぶれていない + +- Elixir(監視・遷移・運用)と Rust(高頻度計算・描画)の分担が明確。 +- `Engine.Game` / `Engine.SceneBehaviour` によってゲーム差し替え可能性が担保されている。 +- VampireSurvivor と MiniShooter の同居実績があり、「汎用化」が口だけではない。 + +### 1.2 パフォーマンス前提の実装が本物 + +- SoA、空間ハッシュ、フリーリスト、SIMD/並列化など、必要な最適化が実コードに入っている。 +- Rust 側で 60Hz ループを主導し、境界呼び出しの粗さを吸収している。 +- 描画スレッド分離・スナップショット化の方針も妥当。 + +### 1.3 ドキュメント品質が高い + +- WHY/STEP/設計資料が揃っており、意思決定の履歴が追える。 +- これは中長期の保守で効く(属人化しにくい)。 + +--- + +## 2. 悪い評価(目をそらすと危ない点) + +### 2.1 いちばん危険: 「デバッグが重すぎる」 + +- NIF 境界を跨ぐ不具合の切り分けコストが高い。 +- Rust panic は本質的に BEAM 側の開発体験を壊しやすい。 +- debug 系の仕組みはあるが、日常開発で「速く原因に辿り着ける」状態にはまだ足りない。 + +**影響**: バグ修正速度が落ち、機能追加の成功率まで下がる。 + +### 2.2 機能より先に保守性が詰まり始めている + +- 中心ファイル・中心処理への責務集中が見える。 +- この状態で 3D / Slot / コンポーネントを同時進行すると、変更リスクが急増する。 + +**影響**: 仕様追加のたびに壊れやすくなり、心理的にも手を入れにくくなる。 + +### 2.3 仕様と実装のズレが残っている + +- Step 47 系(Skeleton / Ghost / Garlic)未完了は、技術的には小さく見えても信頼性には効く。 +- ドキュメント読者に「実装済み」と誤解を与える余地がある。 + +**影響**: 開発判断の前提が揃わず、優先順位の議論がぶれる。 + +### 2.4 チーム拡張耐性は高くない + +- Elixir + Rust の複合開発は強力だが、学習コストも高い。 +- 個人/少人数なら回るが、人数増加時のオンボーディング負荷は大きい。 + +**影響**: スケールしたくなった時に採用・育成がボトルネックになる。 + +--- + +## 3. 判定(5段階) + +| 観点 | 評価 | コメント | +|---|---|---| +| アーキテクチャ妥当性 | A | 方針は明確で合理的 | +| 実装完成度(2D現行範囲) | B+ | コアは強いが未完了項目あり | +| 性能設計 | A- | 実装は良い。今後は観測性強化が鍵 | +| 保守性 | C+ | 責務集中と境界デバッグが重い | +| 開発体験 | C | 調査速度が遅くなりやすい | +| 将来拡張の安全性 | C | 今のまま機能追加すると危険 | + +--- + +## 4. 今やるべきこと(優先順位つき) + +### 最優先(1〜2スプリント) + +1. **デバッグ導線の改善** + - Rust ログと Elixir ログを一元的に追える形へ寄せる。 + - 「落ちた時に何を見るか」を手順化して短縮する。 +2. **責務分割の先行投資** + - 中心処理の分解を先に進める(大機能追加より前)。 +3. **Step 47 完了で仕様整合** + - Skeleton / Ghost / Garlic を完了し、ドキュメントと実装の差分を閉じる。 + +### 次点(次四半期) + +4. **結合/E2E テストの追加** + - 起動→プレイ→遷移→ゲームオーバーまでの回帰を自動化。 +5. **3D と Slot は同時着手しない** + - どちらか片方を先行し、もう片方は設計検証に留める。 + +--- + +## 5. 経営的・プロダクト的観点での率直評価 + +- このプロジェクトは「技術力の証明」としては既に強い。 +- しかし、プロダクトとして継続的に機能を積むフェーズへ入るには、今の開発体験は重い。 +- つまり課題は「性能」ではなく、**変更容易性と不具合調査速度**。 + +言い換えると: + +> 速く動くエンジンはできている。 +> 次は「速く直せるエンジン」にする段階。 + +--- + +## 6. 最終コメント(忌憚なく) + +このプロジェクトは、発想・実装力・継続力の3点で明確に高水準。 +一方で、ここから先は「新機能を作る力」よりも「壊さず進める力」が勝負になる。 + +**いま拡張を急ぐより、保守性とデバッグ性に2〜4週間投資した方が、最終到達速度は確実に上がる。** diff --git a/docs/06_system_design/ARCHITECTURE_FILE_LEVEL_CURRENT.md b/docs/06_system_design/ARCHITECTURE_FILE_LEVEL_CURRENT.md new file mode 100644 index 0000000..c69e1bc --- /dev/null +++ b/docs/06_system_design/ARCHITECTURE_FILE_LEVEL_CURRENT.md @@ -0,0 +1,400 @@ +# ファイル単位アーキテクチャ(現状) + +図解版(Mermaid): `docs/06_system_design/ARCHITECTURE_FILE_LEVEL_DIAGRAMS.md` + +最終更新: 2026-02-25 + +本ドキュメントは、以下ディレクトリの**現状の実装依存**をファイル単位で整理したもの。 + +- `lib/app` +- `lib/engine` +- `lib/games` +- `native/game_core/src` +- `native/game_native/src` + +--- + +## 1. 全体像(Elixir <-> Rust 境界) + +```text +Elixir層 + lib/app/application.ex + -> Engine系プロセス起動(SceneManager, GameEvents管理, EventBus, Telemetry等) + lib/app/nif_bridge.ex + <-> Rustlerで native/game_native をロード + <-> Elixir.App.NifBridge としてNIF API公開 + +Rust層 + native/game_native/src/lib.rs + -> rustler::init!("Elixir.App.NifBridge", load = nif::load) + -> nif/* が Elixir公開関数を実装 + -> world/* + game_logic/* + renderer/* + render_thread.rs + -> game_core を利用 + +共通コア層 + native/game_core/src/* + -> 定数、パラメータテーブル、物理プリミティブ、ユーティリティ +``` + +--- + +## 2. `lib/app`(ファイル単位) + +```text +lib/app/application.ex + -> Registry(name: Engine.RoomRegistry) + -> Engine.SceneManager + -> Engine.InputHandler + -> Engine.EventBus + -> Engine.RoomSupervisor + -> Engine.StressMonitor + -> Engine.Stats + -> Engine.Telemetry + -> Engine.RoomSupervisor.start_room(:main) + -> 環境変数 GAME_ASSETS_ID 設定 + +lib/app/nif_bridge.ex + -> use Rustler, crate: :game_native + -> NIF公開関数群(create_world, physics_step, start_render_thread等) + <- native/game_native/src/lib.rs の rustler::init と接続 +``` + +--- + +## 3. `lib/engine`(ファイル単位) + +```text +lib/engine/game.ex + -> Engine.Game behaviour定義(ゲーム実装契約) + +lib/engine/scene_behaviour.ex + -> Engine.SceneBehaviour定義(シーン実装契約) + +lib/engine/scene_manager.ex + -> configの :game, :current からゲームモジュール取得 + -> game.initial_scenes() をシーンスタック化 + +lib/engine/game_events.ex [中心] + -> Engine.create_world / set_map_obstacles / create_game_loop_control + -> Engine.start_rust_game_loop / start_render_thread + -> Engine.SceneManager (current/push/pop/replace/update) + -> Engine.EventBus.broadcast + -> Engine.FrameCache.put + -> Engine.InputHandler.get_move_vector(非main) + -> Engine.SaveManager系API(Engine経由) + -> App.NifBridge.get_frame_metadata / get_weapon_levels(直接参照あり) + +lib/engine/event_bus.ex + -> subscribeされたプロセスへ {:game_events, events} を配信 + +lib/engine/frame_cache.ex + <- GameEventsが更新 + -> StressMonitorが参照 + +lib/engine/input_handler.ex + -> ETS :input_state を管理 + <- GameEventsが移動ベクトル取得 + +lib/engine/map_loader.ex + <- GameEvents.init で障害物ロード + +lib/engine/room_registry.ex + <-> Registry API(room_id -> pid) + +lib/engine/room_supervisor.ex + -> DynamicSupervisor + -> Engine.GameEvents をルーム単位で起動停止 + -> Engine.RoomRegistry 参照 + +lib/engine/save_manager.ex + -> App.NifBridge.get_save_snapshot / load_save_snapshot + -> ファイル保存(saves/*) + +lib/engine/stats.ex + -> Engine.EventBus.subscribe + <- EventBusのイベントを集計 + +lib/engine/stress_monitor.ex + -> Engine.FrameCache.get + -> パフォーマンスログ出力 + +lib/engine/telemetry.ex + -> Telemetry.Metrics.ConsoleReporter +``` + +補足: `lib/engine.ex` は公開APIファサードとして `App.NifBridge` / `SceneManager` / `SaveManager` / `RoomSupervisor` を仲介する。 + +--- + +## 4. `lib/games`(ファイル単位) + +### 4.1 `mini_shooter` + +```text +lib/games/mini_shooter/game.ex + -> @behaviour Engine.Game + -> initial_scenes: Playing + -> physics_scenes: Playing + +lib/games/mini_shooter/spawn_system.ex + -> Engine.get_enemy_count + -> Engine.spawn_enemies + +lib/games/mini_shooter/scenes/playing.ex + -> Engine.is_player_dead? + -> SpawnSystem.maybe_spawn + -> transition: GameOverへreplace + +lib/games/mini_shooter/scenes/game_over.ex + -> ゲームオーバー状態維持 +``` + +### 4.2 `vampire_survivor` + +```text +lib/games/vampire_survivor/game.ex + -> @behaviour Engine.Game + -> シーン参照(Playing/LevelUp/BossAlert/GameOver) + -> SpawnSystem.wave_label + -> LevelSystem.weapon_label + +lib/games/vampire_survivor/spawn_system.ex + -> Engine.get_enemy_count + -> Engine.spawn_enemies / spawn_elite_enemy + +lib/games/vampire_survivor/level_system.ex + -> 武器候補生成(純関数) + +lib/games/vampire_survivor/boss_system.ex + -> ボス出現判定(純関数) + +lib/games/vampire_survivor/scenes/playing.ex + -> Engine.is_player_dead? + -> BossSystem.check_spawn + -> LevelSystem.generate_weapon_choices + -> SpawnSystem.maybe_spawn + -> Engine.get_level_up_data / skip_level_up + -> transition: push/replace + +lib/games/vampire_survivor/scenes/level_up.ex + -> 一定時間で :pop(auto_select) + +lib/games/vampire_survivor/scenes/boss_alert.ex + -> BossSystem.alert_duration_ms + -> Engine.spawn_boss + +lib/games/vampire_survivor/scenes/game_over.ex + -> ゲームオーバー状態維持 +``` + +--- + +## 5. `native/game_core/src`(ファイル単位) + +```text +native/game_core/src/lib.rs + -> boss/constants/enemy/entity_params/item/physics/util/weapon を公開 + +native/game_core/src/constants.rs + -> 画面・物理・戦闘定数 + +native/game_core/src/entity_params.rs + -> Enemy/Weapon/Boss のIDベーステーブル(現行主要経路) + +native/game_core/src/item.rs + -> ItemKind + ItemWorld(SoA) + +native/game_core/src/weapon.rs + -> WeaponSlot + weapon_upgrade_desc + -> constants/entity_params 参照 + +native/game_core/src/util.rs + -> exp_required_for_next / spawn_position_around_player + +native/game_core/src/physics/mod.rs + -> obstacle_resolve / rng / separation / spatial_hash + +native/game_core/src/physics/rng.rs + -> SimpleRng + +native/game_core/src/physics/spatial_hash.rs + -> SpatialHash + CollisionWorld(動的/静的) + +native/game_core/src/physics/separation.rs + -> EnemySeparation trait + apply_separation + +native/game_core/src/physics/obstacle_resolve.rs + -> resolve_obstacles_player + +native/game_core/src/enemy.rs, boss.rs + -> Enum中心の旧来定義(entity_paramsとの併存) +``` + +--- + +## 6. `native/game_native/src`(ファイル単位) + +### 6.1 入口・NIF公開 + +```text +native/game_native/src/lib.rs + -> mod asset/audio/game_logic/nif/renderer/render_snapshot/render_thread/world + -> rustler::init!("Elixir.App.NifBridge", load = nif::load) + -> atoms定義(ok, frame_events, ui_action, enemy_killed等) + +native/game_native/src/nif/mod.rs + -> action_nif / game_loop_nif / load / render_nif / read_nif / save_nif / util / world_nif + +native/game_native/src/nif/load.rs + -> Resource登録(GameWorld, GameLoopControl) + -> アトム事前登録 + +native/game_native/src/nif/world_nif.rs + -> create_world / set_player_input / spawn_enemies / set_map_obstacles + +native/game_native/src/nif/game_loop_nif.rs + -> physics_step_inner + drain_frame_events_inner + -> start_rust_game_loop(スレッド) + -> pause_physics / resume_physics + +native/game_native/src/nif/action_nif.rs + -> add_weapon / skip_level_up / spawn_boss / spawn_elite_enemy + +native/game_native/src/nif/read_nif.rs + -> get_frame_metadata / get_level_up_data / get_weapon_levels ほか read API + +native/game_native/src/nif/save_nif.rs + -> SaveSnapshot定義 + -> get_save_snapshot / load_save_snapshot + +native/game_native/src/nif/render_nif.rs + -> render_thread::run_render_thread 起動(単一起動ガード) +``` + +### 6.2 ワールドモデル + +```text +native/game_native/src/world/mod.rs + -> boss/bullet/enemy/frame_event/game_loop_control/game_world/particle/player + +native/game_native/src/world/game_world.rs + -> GameWorldInner(全状態) + -> complete_level_up / rebuild_collision + +native/game_native/src/world/player.rs + -> PlayerState + +native/game_native/src/world/enemy.rs + -> EnemyWorld(SoA) + EnemySeparation実装 + +native/game_native/src/world/bullet.rs + -> BulletWorld(SoA) + BULLET_KIND_* 定数 + +native/game_native/src/world/particle.rs + -> ParticleWorld(SoA) + +native/game_native/src/world/boss.rs + -> BossState + +native/game_native/src/world/frame_event.rs + -> FrameEvent enum + +native/game_native/src/world/game_loop_control.rs + -> pause/resume制御 +``` + +### 6.3 ロジック・描画 + +```text +native/game_native/src/game_logic/mod.rs + -> chase_ai / events / physics_step + +native/game_native/src/game_logic/chase_ai.rs + -> 追尾AI + 最近接探索 + SIMD/並列処理 + +native/game_native/src/game_logic/events.rs + -> FrameEvent -> Elixir送信用Tuple変換 + +native/game_native/src/game_logic/physics_step.rs [中心] + -> world更新(移動、衝突、武器、ボス、ドロップ、イベント) + -> game_core::constants/entity_params/item/physics/util を大量利用 + +native/game_native/src/render_snapshot.rs + -> GameWorldInner -> RenderSnapshot 変換 + +native/game_native/src/render_thread.rs + -> winit EventLoop + -> build_render_snapshot + -> renderer.update_instances/render + -> UIアクションをworldへ反映 + +native/game_native/src/renderer/mod.rs + -> wgpu描画 + egui HUD/UI + -> sprite.wgsl 利用 + +native/game_native/src/renderer/shaders/sprite.wgsl + -> インスタンススプライト描画シェーダ + +native/game_native/src/asset/mod.rs + -> AssetLoader(実ファイル優先 + 埋め込みフォールバック) + +native/game_native/src/audio.rs + -> rodioによるBGM/SE再生 +``` + +--- + +## 7. アーキテクチャ評価(強み / 弱み) + +### 7.1 強み + +1. **層分離が明確** + Elixirは運用・遷移・監視、Rustは高頻度計算と描画に集中している。 + +2. **NIF境界が明確** + `lib/app/nif_bridge.ex` と `native/game_native/src/lib.rs` の対応が分かりやすい。 + +3. **OTP活用が適切** + `GameEvents`、`EventBus`、`RoomSupervisor`、`Stats`、`StressMonitor` が分離され、障害局所化しやすい。 + +4. **データ指向で性能に強い** + `EnemyWorld` / `BulletWorld` / `ParticleWorld` が SoA + free list で高負荷に耐えやすい。 + +5. **ゲーム差し替え可能性** + `Engine.Game` / `Engine.SceneBehaviour` によってゲーム固有実装を差し替えられる。 + +### 7.2 弱み + +1. **`physics_step.rs` の責務集中** + 単一ファイルに複数責務が集まり、保守と安全な変更が難しい。 + +2. **ドメイン定義の二重化** + `game_core` 内で `enemy.rs`/`boss.rs` と `entity_params.rs` が併存し、将来の不整合リスクがある。 + +3. **境界一貫性の揺れ** + 一部で `Engine` ファサードを通さず `App.NifBridge` 直接参照があり、抽象層の統一が崩れやすい。 + +4. **文字列ベースUIアクション** + `"__save__"` 等の文字列プロトコルは型安全性が低い。 + +5. **`GameWorld` 単一ロック依存** + `RwLock` に loop/write と render/read が集中し、将来スケールで競合増の可能性がある。 + +6. **描画モジュール責務過多** + `renderer/mod.rs` がレンダリング基盤とゲームUIを同居させている。 + +--- + +## 8. 重要ハブ(変更影響が大きい順) + +1. `native/game_native/src/game_logic/physics_step.rs` +2. `lib/engine/game_events.ex` +3. `native/game_native/src/world/game_world.rs` +4. `native/game_native/src/renderer/mod.rs` +5. `native/game_native/src/render_thread.rs` +6. `native/game_native/src/nif/read_nif.rs` +7. `native/game_native/src/nif/world_nif.rs` +8. `lib/engine/scene_manager.ex` +9. `native/game_core/src/entity_params.rs` +10. `lib/engine.ex` + diff --git a/docs/06_system_design/ARCHITECTURE_FILE_LEVEL_DIAGRAMS.md b/docs/06_system_design/ARCHITECTURE_FILE_LEVEL_DIAGRAMS.md new file mode 100644 index 0000000..99f4890 --- /dev/null +++ b/docs/06_system_design/ARCHITECTURE_FILE_LEVEL_DIAGRAMS.md @@ -0,0 +1,361 @@ +# ファイル単位アーキテクチャ図解(Mermaid版) + +最終更新: 2026-02-25 + +対象: + +- `lib/app` +- `lib/engine` +- `lib/games` +- `native/game_core/src` +- `native/game_native/src` + +--- + +## 1) 全体構成(Elixir <-> Rust) + +```mermaid +flowchart LR + subgraph ELX[Elixir] + A1[lib/app/application.ex] + A2[lib/app/nif_bridge.ex] + E0[lib/engine.ex] + E1[lib/engine/game_events.ex] + E2[lib/engine/scene_manager.ex] + E3[lib/engine/event_bus.ex] + E4[lib/engine/frame_cache.ex] + E5[lib/engine/room_supervisor.ex] + end + + subgraph RST[Rust native/game_native] + R0[src/lib.rs rustler::init] + R1[src/nif/*] + R2[src/world/*] + R3[src/game_logic/*] + R4[src/render_thread.rs] + R5[src/render_snapshot.rs] + R6[src/renderer/mod.rs] + end + + subgraph CORE[shared native/game_core] + C0[src/constants.rs] + C1[src/entity_params.rs] + C2[src/physics/*] + C3[src/util.rs] + C4[src/weapon.rs] + C5[src/item.rs] + end + + A1 --> E2 + A1 --> E3 + A1 --> E5 + E1 --> E0 + E0 --> A2 + A2 --> R0 + R0 --> R1 + R1 --> R2 + R1 --> R3 + R1 --> R4 + R4 --> R5 + R4 --> R6 + + R2 --> C1 + R3 --> C0 + R3 --> C1 + R3 --> C2 + R3 --> C3 + R6 --> C0 + R6 --> C4 + R2 --> C5 +``` + +--- + +## 2) `lib/app`(ファイル単位) + +```mermaid +flowchart TD + AP[application.ex] + NB[nif_bridge.ex] + + AP --> RR[Engine.RoomRegistry] + AP --> SM[Engine.SceneManager] + AP --> IH[Engine.InputHandler] + AP --> EB[Engine.EventBus] + AP --> RS[Engine.RoomSupervisor] + AP --> ST[Engine.Stats] + AP --> TM[Engine.Telemetry] + AP --> MON[Engine.StressMonitor] + AP --> MAIN[start_room :main] + + NB -->|Rustler crate game_native| RLIB[native/game_native/src/lib.rs] +``` + +--- + +## 3) `lib/engine`(ファイル単位) + +```mermaid +flowchart TD + GEV[game_events.ex] + ENG[lib/engine.ex API facade] + GSM[scene_manager.ex] + GSB[scene_behaviour.ex] + GGB[game.ex behaviour] + EBUS[event_bus.ex] + FC[frame_cache.ex] + IH[input_handler.ex] + ML[map_loader.ex] + RR[room_registry.ex] + RS[room_supervisor.ex] + SV[save_manager.ex] + ST[stats.ex] + SM[stress_monitor.ex] + TEL[telemetry.ex] + + GEV --> ENG + GEV --> GSM + GEV --> EBUS + GEV --> FC + GEV --> IH + GEV --> ML + GEV --> RR + GEV --> SV + + RS --> RR + RS --> GEV + + ST --> EBUS + SM --> FC + + GSM --> GGB + GEV --> GGB + GEV --> GSB + TEL --> TMR[Telemetry.Metrics.ConsoleReporter] +``` + +--- + +## 4) `lib/games`(ファイル単位) + +```mermaid +flowchart LR + subgraph MINI[games/mini_shooter] + M0[game.ex] + M1[spawn_system.ex] + M2[scenes/playing.ex] + M3[scenes/game_over.ex] + M0 --> M2 + M0 --> M3 + M2 --> M1 + end + + subgraph VS[games/vampire_survivor] + V0[game.ex] + V1[spawn_system.ex] + V2[level_system.ex] + V3[boss_system.ex] + V4[scenes/playing.ex] + V5[scenes/level_up.ex] + V6[scenes/boss_alert.ex] + V7[scenes/game_over.ex] + + V0 --> V4 + V0 --> V5 + V0 --> V6 + V0 --> V7 + V4 --> V1 + V4 --> V2 + V4 --> V3 + V6 --> V3 + end +``` + +--- + +## 5) `native/game_core/src`(ファイル単位) + +```mermaid +flowchart TD + L[lib.rs] + K[constants.rs] + P[entity_params.rs] + I[item.rs] + W[weapon.rs] + U[util.rs] + E[enemy.rs] + B[boss.rs] + + PM[physics/mod.rs] + PR[rng.rs] + PSH[spatial_hash.rs] + PSEP[separation.rs] + POB[obstacle_resolve.rs] + + L --> K + L --> P + L --> I + L --> W + L --> U + L --> E + L --> B + L --> PM + + PM --> PR + PM --> PSH + PM --> PSEP + PM --> POB + + W --> K + W --> P + U --> K +``` + +--- + +## 6) `native/game_native/src`(ファイル単位) + +```mermaid +flowchart TD + L[src/lib.rs] + + subgraph NIF[nif] + N0[nif/mod.rs] + N1[nif/load.rs] + N2[nif/world_nif.rs] + N3[nif/game_loop_nif.rs] + N4[nif/action_nif.rs] + N5[nif/read_nif.rs] + N6[nif/save_nif.rs] + N7[nif/render_nif.rs] + N8[nif/util.rs] + end + + subgraph WORLD[world] + W0[world/mod.rs] + W1[world/game_world.rs] + W2[world/player.rs] + W3[world/enemy.rs] + W4[world/bullet.rs] + W5[world/particle.rs] + W6[world/boss.rs] + W7[world/frame_event.rs] + W8[world/game_loop_control.rs] + end + + subgraph LOGIC[game_logic] + G0[game_logic/mod.rs] + G1[chase_ai.rs] + G2[events.rs] + G3[physics_step.rs] + end + + subgraph RENDER[render] + R1[render_thread.rs] + R2[render_snapshot.rs] + R3[renderer/mod.rs] + R4[renderer/shaders/sprite.wgsl] + end + + A1[asset/mod.rs] + AU[audio.rs] + + L --> N0 + L --> W0 + L --> G0 + L --> R1 + L --> R2 + L --> R3 + L --> A1 + L --> AU + + N0 --> N1 + N0 --> N2 + N0 --> N3 + N0 --> N4 + N0 --> N5 + N0 --> N6 + N0 --> N7 + N0 --> N8 + + N2 --> W1 + N3 --> G3 + N3 --> G2 + N4 --> W1 + N5 --> W1 + N6 --> W1 + N7 --> R1 + + W0 --> W1 + W0 --> W2 + W0 --> W3 + W0 --> W4 + W0 --> W5 + W0 --> W6 + W0 --> W7 + W0 --> W8 + + G0 --> G1 + G0 --> G2 + G0 --> G3 + G3 --> W1 + G1 --> W3 + + R1 --> R2 + R1 --> R3 + R3 --> R4 + R2 --> W1 +``` + +--- + +## 7) 実行シーケンス(1フレーム) + +```mermaid +sequenceDiagram + participant App as application.ex + participant GE as game_events.ex + participant NIF as nif/game_loop_nif.rs + participant PHY as game_logic/physics_step.rs + participant EVT as game_logic/events.rs + participant SCN as scene_manager + scenes/* + participant REN as render_thread.rs + participant RS as render_snapshot.rs + participant RD as renderer/mod.rs + + App->>GE: 起動(:main room) + GE->>NIF: start_rust_game_loop(world, control, pid) + loop 60Hz + NIF->>PHY: physics_step_inner() + PHY->>EVT: frame_events生成 + NIF-->>GE: {:frame_events, events} + GE->>SCN: current scene update/transition + end + + par 描画ループ + GE->>NIF: start_render_thread(world) + REN->>RS: build_render_snapshot(world.read) + REN->>RD: update_instances + render + RD-->>REN: UI action(optional) + REN-->>GE: {:ui_action, action} + end +``` + +--- + +## 8) 評価(強み / 弱み) + +### 強み + +- Elixir(運用・遷移)とRust(高頻度計算・描画)の責務分離が明確。 +- NIF境界が `nif_bridge.ex` と `src/lib.rs` で一意に追える。 +- OTPプロセス分離(`GameEvents`、`EventBus`、`Stats`、`StressMonitor`)が効いている。 +- SoA + free list により `world/*` が高負荷時に安定しやすい。 + +### 弱み + +- `game_logic/physics_step.rs` に責務が集中(変更影響が大きい)。 +- `game_core` で `enemy.rs`/`boss.rs` と `entity_params.rs` が併存。 +- UI action が文字列プロトコルで型安全性が低い。 +- `GameWorld` 単一 `RwLock` に read/write 競合点が集まりやすい。 +