【続編!】音ゲーって作れるの?2
_人人人人人人人人人_
> 突然の続編!! <
 ̄Y^Y^Y^Y^Y^Y^Y^Y ̄
はじめに
どうも、プログラミング班元班長の鈴木です。
突然の投稿になりますが......なんと今回はこちらの記事、「音ゲーって作れるの?」の続編を書こう!と唐突に思ったので急遽筆を執った次第です。次回のブログリレーまで待ちきれず書いてしまうことにしました(笑)
こちらの記事ですが、私が初めて書いた記事であるにも関わらず、未だに多くの方にご覧いただけているようでありがたい限りです。ほんとに。
さて、今回は音ゲーを作るにあたって前回の記事だけでは説明しきれなかった部分についてありがちな失敗例なども載せて解説してみようと思っております。
今回もいつもの如く、プログラムのスクリプトは一切登場しません。音ゲーを作る時に必要な考え方を紹介していく形ですね。
(今回は前回の記事の内容を踏まえた上で書いていきますので、できれば前回の記事を先に読んでいただいてから今回の記事を読むことをおすすめします。)
音ゲーって作れるの!?
作れますよ、音ゲーは。
前回は、ノーツの判定をする方法を簡単に解説していきましたが、そのノーツをどう動かしたら良いかについては解説をしていませんでした。
今回はノーツの動かし方について解説していきます!
ノーツの動かし方
前回の記事でノーツの判定の仕方がわかったとしても、あれは言ってしまえば内部の判定の話であって画面に直接出る情報ではありませんでしたよね。
判定するタイミングの計算方法はわかったけど、じゃあそのノーツはどう配置して動かせばいいんだよ!と。
ここでは、ありがちなミスを例にしながらノーツの動かし方を解説していきます。
*はじめに
今回はこのような音ゲーの模式図を使って説明していきます。
上から下に向かってノーツが落ちていくタイプの音ゲーです。
杞憂さんの記事に登場する音ゲーと同じタイプです。
> OpenSiv3Dで音ゲーのような何かをつくってみる【サマーブログリレー2019 9日目】 - ICON公式ブログ
ありがちなミス!
例えば下図の例で考えてみましょう。
・判定枠から400px離れた位置にノーツを生成するとします
・このノーツを叩くべきタイミングは2.0秒後です
・このゲームはフレームレート60FPSで動きます
さて、この場合、ノーツをどのように動かせばよいのでしょうか?
単純に考えるのならば、2秒=120フレームで400px動かせば良いわけですから、ノーツを1フレームあたり3.3333pxずつ移動させていけばよいですね。
さて、この実装で本当に大丈夫でしょうか...?
実はこの実装方法ではダメなんです...!!
フレームレートというのは常に完全に一定な値を取るわけではありません。
これは〇〇FPSに固定するという処理をプログラムに書いていたとしてもです。
例えば60FPSに固定するようにしていたとしても、実際のフレームレートには人間の目では判別がつかない程度の誤差が発生します。一瞬だけ59FPSになったり60.5FPSになったりすることがあります。
1FPSずれただけ...?それなら別に良くね?と思うかもしれませんが、音ゲーというのは一瞬の時間のやりとりが行われるゲームです。
0.01秒ずれただけでも判定が1段階ずれてしまうことがありますし、0.1秒もずれれば曲と譜面のタイミングにずれを感じるくらいになります。
更に、この方法で実装した音ゲーをスペック不足のPCでプレイした場合、フレームレートのずれはより大きなものになります。場合によってはまともにプレイできないくらいタイミングがずれてしまう恐れがあるのです!
そして何より、このずれは曲が先に進むほど蓄積されていき、最終的にはノーツのタイミングと曲がズレまくっているという悪夢が起こる場合もあります。*1
改善方法!
ノーツを1フレームあたり〇pxずつずらしていく、つまりノーツに一定の移動速度を持たせる方法ではずれが発生する恐れがあることがわかりました。
こちらの改善方法はズバリ、時間を使う事です!
時間。前回の記事でも登場しました。
そうなんです、音ゲーでは時間を使って制作することがかなり重要なんです!
ノーツの座標を時間の関数で表すことで、ノーツを正しく動かすことが可能です。
下図で考えてみましょう。
登場する変数を詳しく説明しておきます。
・t : ゲーム開始からの経過時間(現在の時間)
・pt : 叩くべき時間(以後、パーフェクトタイミングと呼びます)
・a : 速度係数、つまり譜面のスクロール速度
ノーツのy座標を、y = 400 - 400 * (pt - t) *2というようにtを使って表すことでフレームレートのずれや、プレイ環境(PCスペック)による誤差を殆ど無くすことが可能です。
この方法の強いところは、フレームレートが変化しても対応できるという点です。
細かいフレームレートの誤差はもちろんのこと、
ゲームのコンフィグ画面でフレームレートを60FPSや30FPSなど可変にしたい場合でもノーツ座標関連のプログラムは一切変更せずにフレームレート変化を実装可能です。
また、PCの不調によりゲームが一瞬フリーズしてしまった場合にも、ノーツ座標は時間に依存しているのでフリーズが解除されればちゃんと正しい座標に戻ってきます。
ここからは、具体的に数値を当てはめて考えてみましょう。
例1)
状況は次の通りです。
・曲が始まってからの時間は10.5秒です (t = 10.5)
・ノーツのパーフェクトタイミングは11.25秒です (pt = 11.25)
1. 現在の状況
y = 400 - 400 * (pt - t)
に先ほどの値を代入してみます。
y = 400 - 400 * (11.25 - 10.5)
= 400 - 300
= 100
つまり、下図のような状況ということになります。
2. ノーツが判定枠に重なるタイミング
ノーツが判定枠に重なるタイミング、つまり t = pt のときです。
y = 400 - 400 * (pt - t)
にこの値を代入してみます。
y = 400 - 400 * (11.25 - 11.25)
= 400 - 0
= 400
つまり、下図のような状況ということになります。
ちゃんと判定枠に重なるようにノーツが落ちてきていますね!
例2)ノーツの速度を可変にしたい場合
例1の音ゲーでは、ノーツが y = 0 から y = 400 まで移動するのに1秒かけて移動します。
この速度では音ゲーが苦手な人向けには難しいかもしれませんし、逆に音ゲーマーは遅すぎると感じてしまうかもしれませんね。
そこで、ノーツのスクロール速度を変える方法をこの例で解説していきます!
状況は次の通りです。
・曲が始まってからの時間は9.25秒です (t = 9.25)
・ノーツのパーフェクトタイミングは11.25秒です (pt = 11.25)
・ ノーツが y = 0 から y = 400 まで移動するのに2秒かかるようにさせたいです (a = 0.5)
1. 現在の状況
y = 400 - 400 * a * (pt - t)
に先ほどの値を代入してみます。
y = 400 - 400 * 0.5 * (11.25 - 9.25)
= 400 - 400
= 0
つまり、下図のような状況ということになります。
パーフェクトタイミングの2秒前に y = 0 の位置にノーツが居ますね!
2. 先ほどから1秒後
先ほどから1秒後、つまり t = 10.25 です。
y = 400 - 400 * a * (pt - t)
に値を代入してみます。
y = 400 - 400 * 0.5 * (11.25 - 10.25)
= 400 - 200
= 200
つまり、下図のような状況ということになります。
初期位置と判定枠の真ん中にノーツが居ますね。
3. ノーツが判定枠に重なるタイミング
ノーツが判定枠に重なるタイミング、つまり t = pt のときです。
y = 400 - 400 * 0.5 * (pt - t)
にこの値を代入してみます。
y = 400 - 400 * (11.25 - 11.25)
= 400 - 0
= 400
つまり、下図のような状況ということになります。
最初から2秒経った後にちゃんとノーツが判定枠のところに来ていますね!
このように、aの値を弄ることで、譜面の速度を上げたり下げたりすることも簡単にできてしまうのです!
おわりに
今回は、「音ゲーって作れるの?」の続編ということで、ノーツ移動時の注意点について書いてみました。
「続編をやるとしたら書きたいこと」自体はかなり前からまとまっていたので、今回の記事はかなりサクサク書くことができました(笑)
今回紹介したノーツ座標の式はあくまでも一例であり、ゲーム内容によっていろいろな表現方法があるかと思います。
とにかくt(時間)を使って表すということが重要なのです。
この記事を通して、音ゲーの作り方に関する疑問が解消されたり、音ゲーがどう動いているのかを知ってもらえたのであれば幸いです。
それでは、また~
さらなる続編は......あるんですかね...!?