VANNAN GAMES.

← 制作ノート一覧

ミュートを押してもBGMが止まらない5つ目の罠と、検索結果を切って直し漏れた話

サイト全体

以前、ブラウザゲームで音が鳴らない罠を4つ書きました。どれも、鳴るはずの音が鳴らない罠で、これで全部のつもりでした。5つ目があったので足します。今度は鳴らないのではなく、止まらないほうです。

前の4つを短く書いておきます。ブラウザで音を鳴らす方法には、HTMLのAudio要素と、音を細かく扱うWeb Audio APIの2つがあります。

OFFにしてもBGMが鳴りつづける

『四十秒の交差点』は、同じ一日を繰り返しながら選択肢で話が分かれていくノベルゲームです。この作品を自分のiPhoneで遊んでいて、画面の隅の♪ボタンを押しました。表示はOFFに変わり、効果音も止まります。BGMだけが鳴りつづけていました。

ボタンを押したときにBGMを消すコードは、こうなっていました。

if (bgmAudio) bgmAudio.volume = bgmMuted ? 0 : BGM_VOLUME;

ミュート中なら音量を0に、そうでなければ決めておいた音量に戻す。この音量の値は0.45です。何もおかしく見えません。パソコンのChromeでは、この書きかたでずっと正しく止まっていました。

iOSでは、ページから音量を変えられない

iOSのSafariでは、Audio要素の音量を決める volume プロパティに値を入れても、音の大きさが変わりません。エラーも警告も出ません。Appleの古い開発者向け資料にも、iOSでは音量はいつも利用者が本体のボタンで決めるもので、JavaScriptからは設定できない、と書いてあります。

音量は利用者が決めるもの、という理屈は分かります。ただ、値を入れても何も言われずに無視されるので、手元のパソコンで試しているあいだは気づけません。

効果音が止まっていたのは、BGMと鳴らしかたが違ったからです。このゲームの効果音はAudio要素を使わず、WAVファイルを読み込んでWeb Audio APIで鳴らしていました。BGMのAudio要素とは別の仕組みです。ミュート中は効果音を鳴らす処理ごと飛ばしていました。音量に0を入れて止めようとしていたのは、BGMだけです。同じボタンで片方だけが止まるので、押した本人にはボタンが壊れているようにしか見えません。

消音には専用の muted プロパティがあって、こちらならiOSでも音が止まります。音量を0にするのではなく、消音のフラグを立てる。ボタンを押したときの行は、こう直しました。

if (bgmAudio) bgmAudio.muted = bgmMuted;

症状から見分ける

この罠は、前の4つと症状の向きが逆なので、切り分けは早いです。

逆に言うと、パソコンだけで試しているうちは、この罠は出ません。iPhoneの実機で♪ボタンを一度押してみるのが、唯一の見つけかたでした。

4本直して、2本残っていた

ここからは、iOSとは関係のない、私の失敗の話です。当時このサイト(VANNAN GAMES)でBGMを鳴らすゲームは8本で、どれもBGMを鳴らすコードをゲームごとのファイルに持っていました。書きかたも似ていたので、1本にあったなら、ほかのゲームにも同じ行があるかもしれません。私はゲームのフォルダ全体で、volume = … ? 0 の形で音量に0を入れている行を検索しました。

『四十秒の交差点』を含めて4本のゲームが出てきたので、全部直して、これで終わりだと思っていました。

翌日、サイト全体を点検していて、まだ2本残っていることに気づきました。『四十秒の交差点』の交差点を舞台にしたワンボタンのアクション『よんじゅうびょう。』と、同じ世界の夜を描いたパズル『よぞらのかけら』です。名前は似ていますが、どれも別の作品です。

残っていた2本も、症状は『四十秒の交差点』と同じでした。『よんじゅうびょう。』は効果音の鳴らしかたも同じでした。『よぞらのかけら』だけは効果音のファイルを持たず、Web Audio APIで波形をその場で作って鳴らしていました。どちらもミュート中は効果音を鳴らす処理ごと飛ばしていたので、やはりBGMだけが残りました。

2本を見落とした原因は、間抜けなものでした。前の日に検索したとき、私は結果を画面に収めるために、出力を先頭の数行だけに切っていました。当たったファイルは6つあって、見えていたのは4つでした。ゲーム1本につき1つのファイルなので、切られた2つのゲームがそのまま残った、というだけの話です。

厄介なのは、出力を切ったせいの見落としが、「直した」という記録と一緒に残ることです。4本直したのは事実で、変更の記録にもそう書きました。でも、あとから読む自分は「全部直った」と受け取ります。次に同じ症状が出たとき、残った2本はもう疑う場所に入っていません。

いまは、こういう一括の書き換えをしたら、書き換えたあとにもう一度、出力を切らずに同じ検索をかけて、0件になるのを確かめるようにしています。件数だけなら、次の1行で出ます。

grep -rlE "volume = .*[mM]uted \? 0" games | wc -l

当たったファイルの数が出るので、0なら残っていません。直す前のコードでこの1行を打つと、6と出ます。作業のあとに見直す自分用の点検リストにも、この確認を足しました。

8本のうち、音量に0を入れていたのが6本で、残りの2本は最初から muted を使っていました。どのゲームも自分のファイルにBGMのコードを持っていたので、同じ直しを6本のゲームのファイルそれぞれに入れることになります。コードが1か所にまとまっていれば、直すのも1か所で済みました。コードを1か所にまとめるかどうかは別の判断です。そもそもの間違いは、6本のゲームに散らばった行を一括で書き換えたのに、全部を直せたかを確かめなかったことでした。

iOSの仕様の罠と、自分の手順の罠

この一件には性質のちがう2つの失敗が入っていました。iOSの仕様を知らなかったことと、直した範囲を確かめなかったこと。

前者は知識で、一度引っかかれば次はありません。この記事もそのために書いています。後者は手順で、知っていても疲れていれば同じことをします。だから覚えるのではなく、確認を手順に入れておくしかない。

ちなみに5つ目の罠を見つけたのは、自分で自分のゲームを遊んでいたときでした。4つ目までも全部そうです。テストで見つかったことは、いまのところ一度もありません。

後日談: BGMのコードを1つにまとめた

ここまでの出来事は8月21日と22日のことです。その1週間後の8月28日に、BGMを鳴らすコードを共通の1ファイルにまとめ、この8本ともそこから鳴らすようにしました。ミュートもそこで muted を使っているので、次に直すときは1か所で済みます。

参考にしたページ