Welcome, Guest. Please login or register.

Login with username, password and session length

 
Advanced search

1411281 Posts in 69324 Topics- by 58380 Members - Latest Member: bob1029

March 28, 2024, 11:14:09 PM

Need hosting? Check out Digital Ocean
(more details in this thread)
TIGSource ForumsDeveloperTechnical (Moderator: ThemsAllTook)Implementing rhythm game time windows?
Pages: [1]
Print
Author Topic: Implementing rhythm game time windows?  (Read 2082 times)
Bryant
Level 0
***



View Profile WWW
« on: August 06, 2016, 05:36:05 PM »

Hello Grin

I'm trying to implement high-precision timing windows for a rhythm game (in Unity/C#, if you're curious), 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:

  • Perfect: Within 1/60th of a second of the target time
  • Great: 2/60th of a second
  • Good: 4/60th of a second
  • Okay: 6/60th of a second
  • Bad: 8/60th of a second
  • 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:
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  Shrug

Thanks in advance!  Kiss
Logged

NoLocality
Level 1
*


AssetsAssetsAssetsAssetsAssets...


View Profile
« Reply #1 on: August 06, 2016, 07:48:00 PM »

If getting the most accurate player score is what you have in mind then maybe give the score a one second delay to resolve as accurately as possible.

Trying to hit your current beat based on the sample rate of the previous is accurate-ish because even if you have a good idea of your current sample rate it's not going to be exactly on the mark.  I doubt this would even be super-noticeable to be honest...maybe.

I would personally delay the player score by one second, this way you would have an accurate way to get the full sample rate vs timing in seconds of the beat the player tried to hit and can resolve more accurately their timing.

I would use your delta method for visual feedback though, obviously not a good idea to keep that on a delay but if you want to be a super-purist about the actual score (very admirable imo) I would give it a delay.


GL with that dude, not many rhythm games being cooked up lately  Coffee
Logged

Friez
Level 0
**



View Profile
« Reply #2 on: August 07, 2016, 03:58:04 AM »

Having worked on Stepmania and a few other rhythm game engines before, I know how nightmarish timing can be.

I've not tried making a rhythm game in unity, but I did make a synthesizer in it for the funsies.

One thing to be mindful when dealing with Unity is how you're accessing your audio, are you simply playing an audio source and reading the AudioSource.timeSamples (https://docs.unity3d.com/ScriptReference/AudioSource-timeSamples.html) value, or are you accessing the audio data via the monobehaviour's OnAudioFilterRead? (https://docs.unity3d.com/ScriptReference/MonoBehaviour.OnAudioFilterRead.html)

With the latter, you can play back an audio clip (or modify existing audio) by manually dishing up the float values for your wave. This will let you get at the frame data that's flying by precisely but I do believe it runs on a separate thread, so you'll have to be mindful of that. You might get more headway with this.

Of course, a number of samples will fly by in course of dishing them up to the sound card every time you process audio, so you'll have to account for that i.e. in the middle of one 'update' a player could have a button seemingly not pressed, but in the next 'update' have it actually pressed - you'll never know at what point they pressed it during the previous update(s) so will probably have to offer up some degree of latency for the player.

There will always be a latency difference between the soundcard getting updated and input device updates, so you'll have to work around that best you can.
« Last Edit: August 07, 2016, 04:05:12 AM by Friez » Logged

Twitter @friezdj
Pages: [1]
Print
Jump to:  

Theme orange-lt created by panic