シーン (タイトル → メニュー → 戦闘 → リザルト…) の切り替えと、シーン内の細かい状態 (idle → attacking → cooldown) は、ジャンルを問わずゲームの背骨です。MitiruEngine はこれを C++ 側で素直に持つことを推奨しています。
- シーン遷移 は
mitiru::scene::SceneRouterでスタック型に積む / 差し替える - シーン内のフェーズ管理 は
mitiru::fsm::StateMachine<EnumT>で enum 駆動の状態機械を持つ - 時間絡みの遷移 は
Timer/Cooldown/Sequenceで待つ
JSON で宣言する rule に逃がしてもいいですが、シンプルな C++ で書くほうが読みやすいというのがエンジンの方針です。
シーンルーター
#include <mitiru/scene/SceneRouter.hpp>
class TitleScene : public mitiru::scene::IScene {
public:
void update(float dt) override { /* ... */ }
void draw(mitiru::Screen& s) override { /* ... */ }
};
class BattleScene : public mitiru::scene::IScene { /* ... */ };
mitiru::scene::SceneRouter router;
router.push(std::make_unique<TitleScene>());
// プレイヤーが「始める」を選んだら
router.replace(std::make_unique<BattleScene>());
// ポーズメニューを上に積む
router.push(std::make_unique<PauseScene>());
// ポーズを閉じる
router.pop();
RPG のシーン階層 (世界 → 街 → 店) も、RTS の (ロビー → マッチ → リザルト) も、シューティングの (タイトル → ステージ → ゲームオーバー) も、すべて同じ push/pop/replace で書けます。
ステートマシン (シーン内のフェーズ)
#include <mitiru/fsm/StateMachine.hpp>
enum class AttackPhase { Idle, Windup, Strike, Recover };
mitiru::fsm::StateMachine<AttackPhase> sm{AttackPhase::Idle};
sm.transition(AttackPhase::Idle, AttackPhase::Windup);
// 0.2s 経過後...
sm.transition(AttackPhase::Windup, AttackPhase::Strike);
// hitbox を有効にして、その後...
sm.transition(AttackPhase::Strike, AttackPhase::Recover);
アクションのコンボ、シミュレーションの建築フェーズ、カードゲームのターン進行、どれにも同じパターンが効きます。
タイマー / クールダウン / シーケンス
mitiru::time::Cooldown fireCooldown{0.25f}; // 4 連射 / 秒
if (mapper.wasPressed(Action::Fire) && fireCooldown.ready()) {
spawnBullet();
fireCooldown.trigger();
}
fireCooldown.update(dt);
mitiru::time::Sequence intro;
intro.then([&]{ showLogo(); }, 1.0f)
.then([&]{ showTitle(); }, 0.6f)
.then([&]{ enableInput(); }, 0.0f);
intro.update(dt);
CEF 側にステートを通知する
シーン状態を HUD や UI に出すとき、JS にロジックを持たせず「C++ が決めた現在値を push して、HTML が表示する」だけにします。
engine.cefContext().executeJavaScript(
"Mitiru.state.set('scene', '" + currentSceneName + "');");
<script>
Mitiru.state.subscribe('scene', name => {
document.getElementById('scene-label').textContent = name;
});
</script>
関連 API
もっと深く知る
- docs/cpp-gameplay-api-gaps.md — C++ gameplay API の現状
- アーキテクチャ