はじめに
「残暑が厳しい」なんて言いますが、言葉の意味として立秋を過ぎた頃からを残暑と言います。2020年ですと8月7日。専ら暑さ真っ盛り。最近だとお盆過ぎたら涼しくなってくるかなーという感じですが、昔はお盆前には涼しくなってきたんですかね。grnishiです。
本題
monaca(cordovaでも良いですが)とphaser3でiOS、Android用のゲームアプリを作っています。
いくつか障壁はあるのですがその中でも音楽の再生周りについて簡単にまとめます。
環境
Cordovaバージョン: 9.0.0
iOSプラットフォーム: 5.1.1
Androidプラットフォーム: 8.1.0
Gradleバージョン: 4.10.3
Xcodeバージョン: 11.3
Monaca Core Utility バージョン 2.1.0
Phaser 3.24.1
普通にPhaser3で音を再生
function preload () { this.load.audio("bgm", [ "assets/audio/bgm.ogg", "assets/audio/bgm.mp3" ]); } function create () { var bgm = this.sound.add("bgm"); bgm.play(); }
普通に再生するならこれで問題ありません。
しかし、ChromeやSafariでは自動再生できません。何かしらタップさせれば良いのですが、起動したらそのままBGM再生というゲームにありがちな表現が出来ません。
iframeで無音を使った回避策も試してみましたがそれでもダメでした。
Mediaプラグイン
Monaca公式ドキュメントにも記載されているMediaプラグインを使った方法。
var bgm= null; document.addEventListener("deviceready", function() { bgm= new Media ("assets/audio/bgm.mp3"); bgm.play({numberOfLoops: 0}); }, false);
これで自動再生は可能になります。しかし、2音同時再生ができません。ゲームを作るのであれば、BGMとSEを同時に鳴らす必要があります。
Cordova Native Audio Plugin
document.addEventListener("deviceready", function() { window.plugins.NativeAudio.preloadComplex("bgm", "assets/audio/bgm.mp3", 1, 1, 0); window.plugins.NativeAudio.play("bgm"); }, false);
これで2音同時再生ができます。しかし、ミュートのスイッチをONにしても音が鳴ります。というわけでres/cordova-plugin-nativeaudio/src/ios/NativeAudio.mの48行目にある
[session setCategory:AVAudioSessionCategoryPlayback error:nil];
をコメントアウトするとOKです。
問題発生
余談ですが、Cordova Native Audio Pluginを入れてAndroid実機で確認すると起動時にクラッシュしました(Android 10)
OSのバージョンが関係あるかわかりませんが。
クラッシュログを確認すると
java.lang.RuntimeException: Unable to resume activity {jp.co.gracetory.hogehoge/jp.co.gracetory.hogehoge.MainActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'boolean java.util.ArrayList.isEmpty()' on a null object reference ~~中略~~ Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'boolean java.util.ArrayList.isEmpty()' on a null object reference at com.rjfun.cordova.plugin.nativeaudio.NativeAudio.onResume(NativeAudio.java:330) ~~後略~~
と出力されていました。
該当のソースコードを確認しました。
327 @Override 328 public void onResume(boolean multitasking) { 329 super.onResume(multitasking); 330 while (!resumeList.isEmpty()) { 331 NativeAudioAsset asset = resumeList.remove(0); 332 asset.resume(); 333 } 334 }
なぜこうなるのかしっかりと調査していませんが、とりあえず修正。
327 @Override 328 public void onResume(boolean multitasking) { 329 super.onResume(multitasking); 330 if (resumeList != null) { 331 while (!resumeList.isEmpty()) { 332 NativeAudioAsset asset = resumeList.remove(0); 333 asset.resume(); 334 } 335 } 336 }
とりあえず起動できました。
どれが良いのか?
作りたいアプリによってどれを使うべきかは異なります。
下記簡単に機能をまとめます。
機能 | Phaser3 | Mediaプラグイン | NativeAudioPlugin |
---|---|---|---|
再生 | 〇 | 〇 | 〇 |
停止 | 〇 | 〇 | 〇 |
一時停止 | 〇 | 〇 | ✕ |
ボリューム変更 | 〇 | 〇 | 〇 |
ミュート | 〇 | △ | △ |
ループ再生 | 〇 | △ | 〇 |
シーク | 〇 | 〇 | ✕ |
ディレイ | 〇 | ✕ | ✕ |
デチューン | 〇 | ✕ | ✕ |
再生速度変更 | 〇 | ✕ | ✕ |
録音 | ✕ | 〇 | ✕ |
Monacaプレビュー | 〇 | 〇 | ✕ |
まとめ
本記事に限らず、オープンソースで活発に開発されているものは実現方法が一つではありません。
しっかりと調査をして、どの技術を採用するべきかを決定するのが重要です。