音は「常に鳴る BGM」と「瞬間的な SE」の 2 種類に整理できれば、ほとんどのジャンルで足ります。MitiruEngine では runtime layer (web/mitiru_runtime/mitiru_audio.js) が CEF 側に薄い API を出しており、C++ から executeJavaScript で再生指示を出すのが基本パターンです。
- アクション / シューティング: SE が高頻度、BGM はステージごとに切り替え
- RPG / シミュレーション: BGM 重視 + UI 操作の SE
- RTS: ユニット選択音 / 命令確認音 / 戦闘 SE が大量
どのジャンルでも、C++ 側のシーン / 状態機械が「今このサウンドを鳴らせ」とトリガし、JS 側は鳴らすだけ、というシグナル指向は変わりません。
CEF 側の最短 API
<script type="module">
import { audio } from '/runtime/mitiru_audio.js';
audio.playBgm('bgm/main_theme', { volume: 0.6, loop: true });
audio.playSe('se/click');
audio.stopBgm({ fade: 0.5 });
</script>
C++ からトリガする
C++ 側がシーン / 状態を持っているので、「戦闘に入ったから BGM 切り替え」「ヒットしたから SE 鳴らす」は C++ 側のロジックから JS を叩きます。
void onBattleStart() {
engine.cefContext().executeJavaScript(
"Mitiru.audio.playBgm('bgm/battle', { volume: 0.7, loop: true });");
}
void onPlayerHit() {
engine.cefContext().executeJavaScript("Mitiru.audio.playSe('se/hit');");
}
マニフェストでまとめる
assets/audio_manifest.json のような形でファイル一覧と既定音量を JSON で持つのが自然です (内容は宣言的なので、ContentLoader<AudioEntry> で読めます)。
{
"bgm/main_theme": { "src": "bgm/main_theme.ogg", "volume": 0.8 },
"se/click": { "src": "se/click.wav", "volume": 1.0 },
"se/hit": { "src": "se/hit.wav", "volume": 0.9 }
}
関連 API
web/mitiru_runtime/mitiru_audio.js— CEF 側オーディオ APImitiru::data::ContentLoader— マニフェスト読み込み
もっと深く知る
- docs/HYBRID_RUNTIME.md — C++ ↔ CEF の責務分担