アマゾンバナーリンク

DXライブラリとC#での音楽ゲームの作り方その6 BMSデータの計算式

今回は時間とテンポの関係から使用する計算式について説明しています。

音ゲーを作るのに非常に重要な部分なのでしっかり理解しましょう。

テンポと時間の関係

まず音ゲーに関連するものといえばテンポという概念です。

テンポが分ればある一定時間たった場合の現在の再生位置というのを求めることが出来ます。例えばテンポが120だとすると、これは1分間に120拍打つ速さということになります。

ちなみに重要な事として時間を絡めた計算は基本的に全て秒で計算する必要があるので、1分後、つまり60秒後は120拍打った状態であるということが分かります。

では逆に30秒目は何拍になるのか求めたい場合はどうするでしょうか。
これは上の図を見ると比較的簡単に分かると思います。

単純に半分の時間なので必然的に拍数も半分の60ということになります。

これらのことからn秒後は何拍なのかという計算式を作ることが出来ます。

まずはテンポが120だった場合の1秒間の拍数を求めます。

1秒間の拍数 = 120 ÷ 60

1秒間の拍数が分かればあとは何秒経過したかを倍率としてかければよいので、
最終的なトータルの拍数は以下の式で求められます。

トータルの拍数 = n × 1秒間の拍数

そして1秒間の拍数の式をそのまま合成すると以下のようになります。

トータルの拍数 = n × (120 ÷ 60)

最後に計算可能な式を展開すると以下のようになり、これは単純な比例関数となります。

トータルの拍数 = n × 2

この式を使えばもっと細かい時間での拍数を計算できます。

例えば0.75秒の時は「0.75×2=1.5拍」、630.58秒の時は「630.58x2=1261.16拍」というように、どの時間でも正確な拍数を求めることが出来ます。

さて、ここではテンポを120と固定にしていたのでこれも可変に出来ればすべてのテンポに対応できます。

そしてその最終的な計算式は以下のようになります。

トータルの拍数 = n × (テンポ数 ÷ 60)

これがまず重要な要素の1つとなります。

BMSデータカウント値と拍数の関係

このサイトで説明しているBMSデータは1小節を9600カウントとして扱っています。そして4/4拍子の場合の1小節とは4回リズムをとったときの長さとなるため、1回のリズム(つまり1拍)をとったときの長さは、9600を4で割った2400カウントとなります。

このことから「1拍は2400カウント」ということが定義されます。

では、経過した時間からBMS上でのカウント値を求めるにはどうするでしょうか。

まずは上記のことから以下のような対比が成り立ちます。

1拍 = 2400カウント

ということは最終的なトータルの拍数に2400をかけることで、BMS上でのカウント値を算出することが出来ます。これを上記の計算式を使って表すと以下のようになります 。

BMSカウント値 = トータルの拍数 × 2400

つまり、最終的に必要な計算式は以下のようになります。

BMSカウント値 = n × (テンポ数 ÷ 60) × 2400

これが一番重要な計算式であり、この原理を確実に理解しておく必要があります。

テンポの途中変更について

上記で説明した計算式はテンポが固定されている場合にのみ正しいカウント数を計算できます。

これはn秒後という値のみを変更できる式のため、もし途中でテンポが変わってしまうと時間は0からの再計算となってしまい、結局は最初から変更後のテンポであるかのように計算されるからです。

以下は最初Tempo120だったものが、途中でTempo200になった時のBMSカウント値を表しています。

これを見るとテンポが変更された瞬間にBMSカウント値が巻き戻っており、このBMSカウント値を使って譜面を表示していたとすると、いきなり譜面が戻ってしまうことになりこれではゲームとして成り立ちません。

そこで考えられることは毎回0からの計算をしなければよいということになります。

そのためにはまず現在のBMSカウント値を記録するための変数を用意します。
そしてメインループでは1つ前のフレーム時間から今回のフレームまでの時間の差分を取り、
その差分時間と現在のテンポ値からBMSカウント値を算出します。

つまりこの値というのは1フレーム分のBMSカウント値となるため、これを最初に用意したBMSカウント変数にどんどん加算していくことで、テンポが変更されても以前のBMSカウント値が戻されてしまうという問題は回避出来ます。

しかしこの方法には1つ重大な問題があります。

ここで説明しているゲームは基本的に60fpsで動作することを前提としていますが、この時の1フレームの間隔はおよそ16.6msとなり、テンポ変更は必ずこの16.6msの間隔でしか処理されないということになります。

このため1回のテンポ変更で最大で16.6msズレることが考えられるため、特にテンポ変更を多用した曲は終盤でかなりのズレが発生することになります。

ということでこの方法も使えないことになるので、また他の方法を考えなければなりません。
そこで次はテンポ変更を考慮したBMSカウント算出アルゴリズムについて説明します。