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);
// 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



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