#ウルトラソウルでもっとハアアアアイィッッッッッッしたい!
「そして輝く?」と言われたら皆さんはなんと答えますか?
そうですね、「ウルトラソウウゥッッッッッ ハアイィッッ」ですよね。
でもその__ハアアアアイィッッッッッッ1回で足りてますか???__
「私、もっとハアアアアイィッッッッッッしたい。。。一回じゃ足らない!!」と悩んでいる方もいらっしゃるのではないでしょうか。
そこで今回はYoutube Player APIを利用して__たくさんハアアアアイィッッッッッッできる__ゲームを作ってみました。
ただハアアアアイィッッッッッッしても面白くないので、音ゲー要素をちょっと入れてみてます。
コードも是非是非ご覧ください!
Appはここから
コードはここから
前回の記事も是非ご覧くださいね。
#完成デモ
##しっかりハアアアアイィッッッッッッ
「結末ばかりに気を取られ」をクリックすると、複数音源から「ウルトラソウル」が一斉に再生されます。
__それぞれの音をしっかり聞き分け、「ハアアアアイィッッッッッッ」のタイミングでハアアアアイィッッッッッッボタンをクリックする__というゲームです。
冒頭に「いくつのソウルでハアアアアイィッしますか」と聞かれるので、そこで選んだ数だけ音源が重なります。
最大8つの音源の聞き分けがクリアできたらハアアアアイィマスターです。
ウルトラソウルハアアアアイィッのハアアアアイィッでハアアアアイィッできる音ゲー作りました。何重にも重なる音源からハアアアアイィッを聞き分けてボタンをクリックしてください!#protoout pic.twitter.com/DEBAoCQPIA
— canonno @クラファンご支援ありがとうございました! (@canonno_blog) December 24, 2020
##ハアアアアイィッッッッッッ判定
調査の結果、今回利用した音源で__「ハアアアアイィッッッッッッ」の「ハ」の「h」のタイミングは67.016秒地点__ということが分かりました。
これと「ハアアアアイィッッッッッッ」を押したタイミングの差に応じて「早すぎる」だとか「遅い」だとか言われます。
例えば5つの音源が再生されている場合、5つの「ハアアアアイィッッッッッッ」全てを一定範囲内のタイミングでクリックする必要があるイメージです。
全ハアアアアイィッのクリック結果を総合した結果が最初に出ますので、是非是非パーフェクト目指して頑張ってみてください。
#実装こまごま
##p5jsまわりYoutube Player APIまわり
これまでの記事でもずっと扱ってきているので、p5jsまわりはこちらの記事を、Youtube Player APIまわりはこちらの記事をご覧ください。
今流行りの湯婆婆関連ゲームも作ったのでこちらの記事も是非是非ご覧になってくださいね。
##複数音源の再生
今回複数のウルトラソウルを同時に流しています。
当初は、例えば音源を3つ再生するときは、1つめのイントロが流れた数秒後に2つめのイントロ、というように開始時間のラグを作る実装を考えていました。
僕の知識の範囲ではsetTimeoutをfor文の中に入れ込めばいいのかなーと思って実装するも、うまく実装ができず。
調べた結果、どうもsetTimeoutを使うのは筋が悪そうな様。
今回はあきらめましたが、次回以降の備忘録としてメモメモ。
・javascriptのsetTimeoutが即実行されてハマった
そもそもsetTimeoutの文法をちゃんと理解してなかった・・・なるほど
・JavaScriptでループ毎に一定時間待つ方法
自分自身を何度も呼び出すという実装。
で結局、ランダムで開始位置を決めて再生する、という手にしました。
その部分がこちら。
//読み込んだ際に最初に走る処理
function onYouTubeIframeAPIReady() {
//playerの定義
player1 = new YT.Player('player1', cond_dic);
player2 = new YT.Player('player2', cond_dic);
player3 = new YT.Player('player3', cond_dic);
player4 = new YT.Player('player4', cond_dic);
player5 = new YT.Player('player5', cond_dic);
player6 = new YT.Player('player6', cond_dic);
player7 = new YT.Player('player7', cond_dic);
player8 = new YT.Player('player8', cond_dic);
player_list= [
{"player":player1,"sec":sec1},
{"player":player2,"sec":sec2},
{"player":player3,"sec":sec3},
{"player":player4,"sec":sec4},
{"player":player5,"sec":sec5},
{"player":player6,"sec":sec6},
{"player":player7,"sec":sec7},
{"player":player8,"sec":sec8},
]}
//結末ばかりに気を取られをクリックするとここが実行される
function startSound(){
//最初のダイアログに入れた値がstageに入り、その回数だけforが回る
for (let idx= 0;idx<stage;idx++){
//forの回数だけplayerにloadVideo&playVideoされる
player_list[idx]["player"].loadVideoById({
videoId:"Ujb-ZeX7Mo8",
startSeconds:player_list[idx]["sec"],
endSeconds:80,
})
player_list[idx]["player"].playVideo();
}
}
開始時間はランダム性をいれたかったのでこんな感じ。
secは音源間の間隔調整のためのパラメータ、baseは全体の開始時間を調整するためのパラメータです。
こう書くことで、最低限sec1<sec2<sec3<・・・sec8となるように実装できます。
こうすれば、player1が一番最初にスタートし、順にplayer2,player3・・・と続くようにできるので、判定処理が簡単にかけるようになるなぁなどと期待していました。
const sec = 1.5
const base = 35
let sec1 = base
let sec2 = base + Math.random() * sec
let sec3= base + sec + Math.random() * sec
let sec4 = base + sec*2 + Math.random() * sec
let sec5 = base + sec*3 + Math.random() * sec
let sec6 = base + sec*4 + Math.random() * sec
let sec7 = base + sec*5 + Math.random() * sec
let sec8 = base + sec*6 + Math.random() * sec
##ハアアアアイィッ判定処理
これがちょっと面倒だった部分。
先ほどsec1<sec2<sec3・・・とすることによって、player1が一番最初にスタートし、順にplayer2,player3・・・と続くようにしました。
ところが実際やってみると、読み込み待ち時間がそれぞれのプレイヤーで異なるため、時々前後が逆転してしまうことが判明。
これを調節するため並び替え処理を組み込んで実装しました。
function stopSound(){
//ハアアアアイィッをクリックした瞬間のすべてのplayerの時間を取得
let player_time_list = []
for (let idx=0;idx<stage;idx++){
player_time_list.push(player_list[idx]["player"].getCurrentTime())
}
//すべてのplayerの時間を並び替える
player_time_list.sort(compare)
//count番目の音源とhai_time(正解時刻)との差を取得
let dif = player_time_list[count]-hai_time;
loss += Math.abs(dif)
result = hantei(dif)
label += "\n"+(count+1)+"ハアィ:"+result
count++
//最終結果発表
if (count == stage){
result = final_result(loss)
label += "\n\n結果:"+result
}
function compare(a,b){
return b- a;
}
}
#さいごに
最近モノづくりモチベが下がるときがあるので、ちょっとクレイジーな__ウルトラソウルdriven__なネタを考えるようにしています。
是非皆様もやる気が出ないときはウルトラソウルしてみてはいかがでしょうか!
最後まで読んでいただきありがとうございました。LGTMしていただけると励みになります!