Skip to content

効果音の再生

効果音はゲームへの没入度を高める上で非常に重要な要素となります。 ブロックくずしにおいても例外ではありません。 例えば、ブロックが壊れる音はプレイヤーに爽快感を与えてくれます。 ボールがパドルや壁に当たる音は、プレイヤーの操作に対するリアクションをより直感的に知覚させてくれます。

本章ではゲームに効果音を追加する方法について説明します。

オーディオファイルの登録

ゲームで実際に鳴らすためのオーディオファイルを用意しましょう。 Akashic Engine では .ogg, .m4a の2種類が必要です。

複数のオーディオファイルを用意するのは手間がかかるため、変換するためのツールである complete-audio (Akashic が提供するコマンドラインツール) を活用します。 complete-audio はオーディオファイルを Akashic Engine がサポートする形式へと変換してくれるツールです。 一般的な形式のオーディオファイルであれば大抵は問題なく利用できるでしょう。

今回は以下のファイルを利用します。 もちろんご自身で制作されたオーディオファイルを利用しても構いません。

ファイル名用途クレジット
se_paddle.mp3パドルとボールの衝突時の効果音-
se_block.mp3ボールとブロックの衝突 (ブロック破壊) 時の効果音-
se_miss.mp3ミスしたときの効果音-
se_finish.mp3終了時の効果音CC BY 2.1 JP (ゴミをゴミ箱に入れるだけのゲーム) より

INFO

クレジットが表記されていない素材はこの記事のために作成したものです。 自由に利用してください。

上記ファイルを右クリック等で保存後、 game.json と同じディレクトリに配置してください。 (まだ assets/ ディレクトリ以下には配置しないでください)

complete-audio をインストールするには、次のコマンドを実行します。

sh
npm install -g @akashic/complete-audio
npm install -g @akashic/complete-audio

INFO

complete-audio の実行には FFmpeg が必要です。 公式サイト などを参考に FFmpeg を導入してください。

インストールが正常に行われたかを確認するために、以下のコマンドを実行します。

sh
complete-audio --version
complete-audio --version

このコマンドは complete-audio のバージョン情報を表示します。 正常にインストールされていれば、バージョン番号 (執筆時点では 2.0.1) が表示されます。 以降の説明ではバージョンが 2.0.1 であることを前提としているため、 2.0.1 よりも小さい場合は上記コマンドで再インストールしておきましょう。

次にオーディオファイルをアセットとして登録します。 追加したオーディオファイルそれぞれでコマンドを実行します。

sh
complete-audio se_paddle.mp3 --output assets/se
complete-audio se_paddle.mp3 --output assets/se
sh
complete-audio se_block.mp3 --output assets/se
complete-audio se_block.mp3 --output assets/se
sh
complete-audio se_miss.mp3 --output assets/se
complete-audio se_miss.mp3 --output assets/se
sh
complete-audio se_finish.mp3 --output assets/se
complete-audio se_finish.mp3 --output assets/se

--output オプションで変換後のファイルの出力先を指定できます。 ここでは直接 assets/se/ に出力しています。

この時点で assets ディレクトリのファイルは以下のようになっています。

assets
├── images
│   ├── breakout_ball.png
│   ├── breakout_block_a.png
│   ├── breakout_block_b.png
│   └── breakout_paddle.png
└── se
    ├── se_block.m4a
    ├── se_block.ogg
    ├── se_finish.m4a
    ├── se_finish.ogg
    ├── se_miss.m4a
    ├── se_miss.ogg
    ├── se_paddle.m4a
    └── se_paddle.ogg
assets
├── images
│   ├── breakout_ball.png
│   ├── breakout_block_a.png
│   ├── breakout_block_b.png
│   └── breakout_paddle.png
└── se
    ├── se_block.m4a
    ├── se_block.ogg
    ├── se_finish.m4a
    ├── se_finish.ogg
    ├── se_miss.m4a
    ├── se_miss.ogg
    ├── se_paddle.m4a
    └── se_paddle.ogg

変換が完了した後は元の .mp3 ファイルは不要となります。 削除してしまっても問題ありません。

最後に、変換したオーディオファイルをアセットとして登録します。 akashic scan asset コマンドを実行します。

sh
akashic scan asset
akashic scan asset

以上で準備が整いました。

効果音の再生

ゲーム内での音声の再生には、オーディオ再生コンテキストを利用します。 シーンでオーディオアセットを読み込むよう、 assetPaths を以下のように修正します。

javascript
    const scene = new g.Scene({
        game,
        assetPaths: [
            "/assets/images/*",
            "/assets/se/*",
        ],
    });
    const scene = new g.Scene({
        game,
        assetPaths: [
            "/assets/images/*",
            "/assets/se/*",
        ],
    });

シーンの読み込み完了直後で se_paddle のオーディオ再生コンテキストを生成します。

javascript
    scene.onLoad.add(() => {
        const sePaddleAsset = scene.asset.getAudio("/assets/se/se_paddle");
        const sePaddle = game.audio.create(sePaddleAsset); // se_paddle のオーディオ再生コンテキストを生成

        ...
    });
    scene.onLoad.add(() => {
        const sePaddleAsset = scene.asset.getAudio("/assets/se/se_paddle");
        const sePaddle = game.audio.create(sePaddleAsset); // se_paddle のオーディオ再生コンテキストを生成

        ...
    });

アセットの取得には getAudio() を使用します。 ただし、画像アセットと違いオーディオアセットの取得時には拡張子を指定していないことに注意してください。 これは、OSやブラウザがサポートするオーディオ形式に差異があり、Akashic Engine はどの形式のオーディオファイルを再生すべきかを内部で自動的に判断しているためです。 この仕組みにより、ゲーム開発者はオーディオ形式の違いや環境による挙動の差異を意識せずに済みます。

オーディオ再生コンテキストの生成には game.audio.create() を利用します。

それでは実際に音を鳴らしてみましょう。 前章で追加したパドルとボールの衝突時の部分に以下のコードを追加します。

javascript
            // ボールとパドルが衝突したとき
            if (intersect(ball, paddle)) {
                const h = 30;
                const direction = normalize([ball.x - paddle.x, -(ball.y - (paddle.y + h))]);
                vx = speed * direction[0];
                vy = speed * direction[1];
                sePaddle.play();
            }
            // ボールとパドルが衝突したとき
            if (intersect(ball, paddle)) {
                const h = 30;
                const direction = normalize([ball.x - paddle.x, -(ball.y - (paddle.y + h))]);
                vx = speed * direction[0];
                vy = speed * direction[1];
                sePaddle.play();
            }

同様にブロックが破壊されたときにも効果音を鳴らしてみます。 scene.onLoad の直後でオーディオ再生コンテキストを生成します。

javascript
    scene.onLoad.add(() => {
        const sePaddleAsset = scene.asset.getAudio("/assets/se/se_paddle");
        const sePaddle = game.audio.create(sePaddleAsset); // se_paddle のオーディオ再生コンテキストを生成
        const seBlockAsset = scene.asset.getAudio("/assets/se/se_block");
        const seBlock = game.audio.create(seBlockAsset); // se_block のオーディオ再生コンテキストを生成

        ...
    });
    scene.onLoad.add(() => {
        const sePaddleAsset = scene.asset.getAudio("/assets/se/se_paddle");
        const sePaddle = game.audio.create(sePaddleAsset); // se_paddle のオーディオ再生コンテキストを生成
        const seBlockAsset = scene.asset.getAudio("/assets/se/se_block");
        const seBlock = game.audio.create(seBlockAsset); // se_block のオーディオ再生コンテキストを生成

        ...
    });

ブロックとボールの衝突時に効果音を鳴らします。

javascript
                if (isCollided) {
                    // 破壊可能のボールと衝突していたら
                    if (block.tag.mapNumber !== 1) {
                        block.destroy(); // ブロックを破壊
                        seBlock.play();
                        break; // 一度のフレームで一つのブロックのみを削除
                    }
                }
                if (isCollided) {
                    // 破壊可能のボールと衝突していたら
                    if (block.tag.mapNumber !== 1) {
                        block.destroy(); // ブロックを破壊
                        seBlock.play();
                        break; // 一度のフレームで一つのブロックのみを削除
                    }
                }

最後にボールを落としてしまった時の効果音を鳴らします。 scene.onLoad の直後でオーディオ再生コンテキストを生成します。

javascript
    scene.onLoad.add(() => {
        const sePaddleAsset = scene.asset.getAudio("/assets/se/se_paddle");
        const sePaddle = game.audio.create(sePaddleAsset); // se_paddle のオーディオ再生コンテキストを生成
        const seBlockAsset = scene.asset.getAudio("/assets/se/se_block");
        const seBlock = game.audio.create(seBlockAsset); // se_block のオーディオ再生コンテキストを生成
        const seMissAsset = scene.asset.getAudio("/assets/se/se_miss");
        const seMiss = game.audio.create(seMissAsset); // se_miss のオーディオ再生コンテキストを生成

        ...
    });
    scene.onLoad.add(() => {
        const sePaddleAsset = scene.asset.getAudio("/assets/se/se_paddle");
        const sePaddle = game.audio.create(sePaddleAsset); // se_paddle のオーディオ再生コンテキストを生成
        const seBlockAsset = scene.asset.getAudio("/assets/se/se_block");
        const seBlock = game.audio.create(seBlockAsset); // se_block のオーディオ再生コンテキストを生成
        const seMissAsset = scene.asset.getAudio("/assets/se/se_miss");
        const seMiss = game.audio.create(seMissAsset); // se_miss のオーディオ再生コンテキストを生成

        ...
    });

ボールが画面の下端に到達したときに効果音を鳴らします。

javascript
            // ボールが画面の下端に到達したとき
            if (ball.y > game.height + ball.height / 2) {
                isStarted = false;
                vx = speed * direction[0];
                vy = speed * direction[1];
                seMiss.play();
            }
            // ボールが画面の下端に到達したとき
            if (ball.y > game.height + ball.height / 2) {
                isStarted = false;
                vx = speed * direction[0];
                vy = speed * direction[1];
                seMiss.play();
            }

番外編: BGM の再生

今回のゲームでは利用しませんが、効果音と同じように BGM を鳴らすこともできます。 しかし BGM の再生には少しだけ追加の設定が必要です。

鳴らしたい BGM のオーディオファイルを complete-audio で変換後、game.json をテキストエディタで開いてください。 "assets" の中から BGM のオーディオアセットの定義 (ここでは assets/bgm/bgm-1) を探し、 systemId の値を初期値の "sound" から "music" に変更してください。 systemId"music" で定義されたオーディオアセットは、自動的にループ再生されるなど BGM に特化した形で利用することができます。

json
{
    "assets": {
        /// ... その他のアセット定義

        "assets/bgm/bgm-1": {
            "type": "audio",
            "path": "audio/bgm/bgm-1",
            "systemId": "sound",
            "systemId": "music",
            "duration": 13120
        }
    }
}
{
    "assets": {
        /// ... その他のアセット定義

        "assets/bgm/bgm-1": {
            "type": "audio",
            "path": "audio/bgm/bgm-1",
            "systemId": "sound",
            "systemId": "music",
            "duration": 13120
        }
    }
}

あとは効果音と同様にオーディオ再生コンテキストを生成し、BGM を鳴らしたいタイミングで play() メソッドを実行するだけです。

javascript
const bgm1Asset = scene.asset.getAudio("/assets/bgm/bgm1");
const bgm1 = game.audio.create(bgm1Asset);
bgm1.play();
const bgm1Asset = scene.asset.getAudio("/assets/bgm/bgm1");
const bgm1 = game.audio.create(bgm1Asset);
bgm1.play();

BGM を止めたい場合はオーディオ再生コンテキストの stop() を実行します。

javascript
bgm1.stop();
bgm1.stop();

実行例とソースコード

Playground で実行