Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Implementing precise rhythm game time windows?

Discussion in 'Scripting' started by bryantdrewjones, Aug 7, 2016.

  1. bryantdrewjones

    bryantdrewjones

    Joined:
    Aug 29, 2011
    Posts:
    147
    Hello :)

    I'm trying to implement high-precision timing windows for a rhythm game, and I'd love to hear how you would all approach the problem.

    Here's where I'm at right now:

    I have 6 tiers of scores that each depend on how close you are to hitting the (right) button at the right time:
    1. Perfect: Within 1/60th of a second of the target time
    2. Great: 2/60th of a second
    3. Good: 4/60th of a second
    4. Okay: 6/60th of a second
    5. Bad: 8/60th of a second
    6. Miss: Anything worse than the above
    In code, rather than expressing these values in seconds, I express everything in samples. The song is played at a certain sample rate (number of samples per second). I know how many samples have been played at any given point during the game, as well as the number of samples played for each of the target times that the player has to tap a button.

    The current song I'm testing is being played at a sample rate of 44100, which means the player only has 735 samples of leeway in order to hit the Perfect time window (Sample Rate * ( 1 / 60 )).

    The problem I'm up against is that the number of samples played per frame isn't actually constant. As an example, assume the game is running at 60FPS, the target beat is on frame N, and the player hits the button on frame N + 1. The player hit the button within 1 frame, so they should receive a Perfect score. But the number of samples played by the audio engine within that time is often greater than the number of samples that should be played within 1/60th of a second (735 samples).

    It's not a big deal in the Perfect scenario; if the time window is 735 samples but the actual sample delta per frame is, say, 1000, I'll still treat that as a Perfect hit:

    Code (CSharp):
    1. int perfectWindowInSamples = (int)( Math.Max( ( 1 / 60d ) * sampleRate, sampleDeltaFromLastFrame );
    But what if the player hits the button on frame N + 2, or N + 4? How do I factor in multiple frames where the number of samples per frame could be more or less than Sample Rate * ( 1 / FrameRate )?

    I have a feeling I ought to store a history of sample deltas per frame (up to as many frames as I care about to assign a proper score) and then factor those numbers in when calculating the actual timing windows for each score tier. But I was hoping I could get another opinion from the forum just to make sure I'm not crazy :eek:

    Thanks in advance! :D