4 / 4 周期と共通の時間軸
秒・拍・Tickを換算して、曲を基準にした共通の時間軸を作ります。
剰余
譜面全体の時間は増え続けますが、拍の中の位置は繰り返します。
増え続ける値から、繰り返しの中の位置を求めるときには剰余の計算を使います。
剰余とは、ある数を別の数で割ったときの余りのことです。
例えば、7を3で割ったときの余りは1です。
C#では7 % 3と書きます。
C# の剰余演算子
C#の%は、割り算の余りを求める演算子です。
例えば、4 Tick/拍の指定の曲で曲の進行Tickが582の場合は、582 % 4 = 2となり、拍のTick位置は2となります。
ここで問題になるのが、負の値の扱いです。
負の値に剰余算すると、結果も負になる場合があります。
例えば-1 % 4は−1です。
C#の剰余演算
ここでは周期の位置をあくまで正のTickで求めたいため、負の結果にTickの値を足して正のTick位置に修正しています。
int tick = (int)currentTick % ticksPerBeat;
if (tick < 0)
tick += ticksPerBeat;サンプルのBeatTickViewでは、さらに小数部分を含むTick位置から拍の中の位置を求めています。
浮動小数点数の剰余を使用すれば、区画の番号だけでなく、拍の途中を進むカーソルの位置も計算できます。
リズムゲームの時間軸をそろえる
ここまでの時間を、曲の開始を0秒とする時間軸へそろえます。譜面では拍とTickを使って位置を決め、ゲームの処理へ渡すときに秒へ換算します。
曲の時刻 = 音声の現在時刻 - 曲の開始時刻
1 Tickの秒数 = 60 / BPM / 1拍のTick数
ノートの判定時刻 = 譜面の開始位置 + 全体のTick番号 × 1 Tickの秒数練習譜面の開始位置は0秒です。ChartSource.FixedChartにあるTickの配列を、配布済みのChartData.Compileがレーンと判定時刻の配列へ変換します。次回は同じ形のデータをCSVから作ります。
RhythmGame.Updateは、1フレームに一度だけ曲の時刻を読み、表示の更新と各レーンの入力判定へ渡します。次も読み取り用の抜粋です。
double songTime = clock.SongTime;
Advance(songTime);
for (int lane = 0; lane < input.LaneCount; lane++)
if (input.WasLanePressed(lane)) PressLane(lane, songTime);この作例の入力時刻は、入力を確認したフレームの曲時刻です。複数のレーンにも同じ値を渡します。Input Systemの入力イベントが持つ時刻を直接使う場合は、曲の時計との対応を別に用意する必要があります。この基本課題では、上の配布済みの処理を使います。
開始後にRを押し、曲と表示秒数が最初へ戻ることを確認してください。音源だけを戻し、曲の開始時刻を前のままにしたら、表示と判定がどうなるか説明してください。
- 全体のTick番号と、拍の中のTick番号を区別できる。
- 再生・表示・判定が共有する時計と開始点をコードで確認した。
- 剰余から拍の中の位置を求め、負の余りを補正する理由を説明できる。