Simple rhythm question.

I'm getting to grips with the basics of making a rhythm game. As a simple test I have an audio clip at 120 bpm running, and when I click a certain object I get a readout of the AudioSource.time value. The idea is that the clicks should land on every half second, say.

I have a good sense of rhythm (!) but I seem to be constantly off by roughly 0.1 seconds and I'm wondering what the source of this is - whether it's just processing time, human reaction time etc, and whether it's normal to have to correct for this in rhythm games.

Any pointers would be greatly appreciated!

Every Rhythm game has Audio and Video calibration settings that you can offset by a number of milliseconds for this exact reason. It's nearly impossible to pinpoint the exact reason that the audio and "click" aren't in sync. I'll list some possible explanations:

  • Your "click" has 0.1s of silence before it
  • Your script takes 0.1s to process before playing the "click" (and the audio is on a different thread)
  • Your specific computer hardware setup has a 0.1s lag between your speakers and your monitor.
  • Your BPM calculation code could be wrong (although at 120bpm (2bps), this is probably unlikely).

You should be using FixedUpdate() as well, for the most precise "game ticks". You can set the Fixed Update interval in your game settings (in the Edit menu). Try lowering or raising it, and see if that makes a difference. (I believe the default is 0.2s, but I could be wrong.)

Making a rhythm game is no easy feat, and I've always wondered if it were possible using Unity's set of audio tools (obviously games like Guitar Hero and Rock Band use a more advanced, feature-ful audio library).

In addition to the issues that SpikeX posted:

  • It takes time for your clicks to be registered and show up as input in the next frame. A higher framerate could help, but you'll still be stuck to the operating system's thread scheduling, which is not always as snappy as you'd like it to be.
  • It takes time for a buffer of audio to be passed to the audio hardware for playback. Using the fairly high-level languages that Unity provides gives you little control over the speed and efficiency with which this happens.

A quick optimization you could try to minimize any lag introduced by your script is to cache the result of GameObject.FindWithTag("120clip").GetComponent(AudioSource) in a variable at start-up. Depending on the complexity of your scene the time required to complete those operations can rise up pretty far.

I think using FixedUpdate could be a good experiment, because then at least you'll have determinate behavior, which could make it easier to compensate for lag.