Rhythm Quest Devlog 8 — Menu Rework

Before and After

New Button Graphics

Music Reactivity

Beat Sync

float GetIntensity(float offset, float patternLength) {
// (Gets the current time, then converts from time to beat)
float beatOffset = MusicController.CurrentBeat();

// Wrap based on beat pattern length and take the difference from our target.
// (note: the % operator will give negative values in C#, so I use a wrapper)
beatOffset = Utils.ModPositive(beatOffset - offset, patternLength);

// Normalize to 0-1 based on duration of the pulse.
float pulseProgress = Mathf.Clamp01(beatTime / _pulseDuration);

// Apply some easing (ease out quad):
pulseProgress = 1.0f - (1.0f - progress) * (1.0f - progress);

// Invert so that we go from 1 to 0 instead of 0 to 1.
return 1.0f - pulseProgress;
_beatDuration * beatLength

Music Transitions

// (Note that this time will never be "exact" since 
// AudioSettings.dspTime runs on a separate timeline)
float currentTime = (float)(AudioSettings.dspTime - _audioDspStartTime);
// (Simple conversion that uses the BPM of the song)
float currentBeat = _song.TimeToBeat(currentTime);
// Find the next downbeat.
float transitionEndBeat = Mathf.CeilToInt(currentBeat);
float transitionEndTime = _song.BeatToTime(transitionEndBeat)
float transitionDuration = transitionEndTime - currentTime;
// We could add the buffer in terms of beats or in terms of seconds.
// Either way is equivalent here since the entire main menu (currently) has constant BPM.
float transitionEndBeat = Mathf.CeilToInt(currentBeat + 0.5f);
  • A transition sweep sfx starts playing immediately at the start of the transition
  • The new music loop needs to be scheduled to kick in at the end of the transition
  • I also schedule a “landing” impact sfx at the end of the transition
  • The old music loop needs to be stopped at the end of the transition
  • The transition sweep sfx fades out quickly during the last sixteenth note of the transition (quarter of a beat)
// Calculate transition "fade start" time, when we want to start
// fading the sweep sfx.
float transitionFadeTime = _song.BeatToTime(transitionEndBeat - 0.25f);
float fadeDuration = _song.BeatToTime(0.25f);
// Play the transition sweep sfx immediately.
// Retain a handle to the AudioSource so we can fade it.
AudioSource sweepAudio = AudioManager.PlaySound(_sweepSfx);
// Schedule landing sfx for end of transition.
AudioManager.PlayScheduled(_transitionEndSfx, _audioDspStartTime + transitionEndTime);
// Schedule new music loop for end of transition.
// We need to queue it up at the appropriate offset first!
_audioSources[newMusicIndex].time = transitionEndTime % _audioSources[newMusicIndex].clip.length;
_audioSources[newMusicIndex].PlayScheduled(_audioDspStartTime + transitionEndTime);
// Loop while transition is happening...
while (AudioSettings.dspTime < _audioDspStartTime + transitionEndTime) {
// How far are we through the fade section?
float timeWithinFade = AudioSettings.dspTime - _audioDspStartTime - transitionFadeTime;
float fadeProgress = Mathf.Clamp01(timeWithinFade / fadeDuration);
// I use an exponent to affect the easing on the fade.
// An exponent of 0.25 makes the fade happen more on
// the tail end (ease in).
sweepSource.volume = Mathf.Pow(1.0f - fadeProgress, 0.25f);
yield return new WaitForEndOfFrame();
// Transition should be done now. Stop the old music loop.

Other Stuff

  • Allowing for menu navigation with keyboard, mouse, gamepad, OR touch input
  • Smartly handling button auto-selection depending on input device (if using keyboard/gamepad, the first option should be highlighted, otherwise not)
  • Supporting localization for all text in the menus, including dynamic text
  • Supporting screen readers so that visually impaired persons can navigate the menu
  • Disallowing menu input while a transition is happening
  • Remembering previous menu selection (returning to a previous menu should preserve the selection state)
  • Allowing for the menu scene to be loaded to a certain state (i.e. when returning from a level, it should have that level preselected)
  • etc…

9-bit chiptune artist and indie game developer — http://ddrkirby.com/

Love podcasts or audiobooks? Learn on the go with our new app.

Recommended from Medium

John Justice, the head of Google’s Stadia product, has left the company.

What makes NieR:Automata so cool? And why can’t I stop talking about it?

Personal Pc Situation - How To Select A Computer Situation

Spanish Armed Forces

The 10 Best AR/VR Apps To Introduce To Your Family

Fortnite’s Civil War: Keyboard and mouse vs. aim assist | Qrank.gg

Gameplay Journal Entry #3

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store


9-bit chiptune artist and indie game developer — http://ddrkirby.com/

More from Medium

React + Node Taking advantage of a shared engine to simplify complex validation.

Testing Beta Version of “Mobile App”

Interview 1 – Mrs Page

Comparing Material UI and Bootstrap