using UdonSharp; using UnityEngine; using VRC.SDKBase; using VRC.Udon; public class SoundManager : UdonSharpBehaviour { [SerializeField] private AudioSource audioSourcePacMan; [SerializeField] private AudioSource audioSourceGhosts; [SerializeField] private AudioSource audioSourceExtraLife; [SerializeField] private AudioClip pacStart; [SerializeField] private AudioClip intermission; [SerializeField] private AudioClip pacDot1; [SerializeField] private AudioClip pacDot2; [SerializeField] private AudioClip pacDie1; [SerializeField] private AudioClip pacFruit; [SerializeField] private AudioClip pacCoin; [SerializeField] private AudioClip pacGhostEat; [SerializeField] private AudioClip pacGhostBlue; [SerializeField] private AudioClip pacGhostRetreat; [SerializeField] private AudioClip pacExtraLife; [SerializeField] private AudioClip siren0; [SerializeField] private AudioClip siren1; [SerializeField] private AudioClip siren2; [SerializeField] private AudioClip siren3; [SerializeField] private AudioClip siren4; private AudioClip _nextDotSound; private bool _ghostRetreating; private bool _ghostBlue; private int _ghostSoundLevel; private bool _currentlyPlayingSiren; private bool _suppress; public void Initialize() { Reset(); } public void Reset() { StopAllSound(); _nextDotSound = pacDot2; _ghostRetreating = false; _ghostBlue = false; _ghostSoundLevel = 0; _currentlyPlayingSiren = false; _suppress = true; } public void SuppressSound(bool suppress) { _suppress = suppress; if (suppress) { StopAllSound(); } } public void PlayGameStartSound() { PlaySound(audioSourcePacMan, pacStart); } public void StartIntermissionSound() { PlaySound(audioSourcePacMan, intermission, true); } public void PlayPelletSound() { PlaySound(audioSourcePacMan, _nextDotSound); _nextDotSound = _nextDotSound == pacDot1 ? pacDot2 : pacDot1; } public void PlayDeathSound() { PlaySound(audioSourcePacMan, pacDie1); } public void PlayFruitSound() { PlaySound(audioSourcePacMan, pacFruit); } public void PlayCoinSound() { PlaySound(audioSourcePacMan, pacCoin); } public void PlayGhostEatSound() { PlaySound(audioSourcePacMan, pacGhostEat); } public void PlayExtraLifeSound() { PlaySound(audioSourceExtraLife, pacExtraLife); } public void StartGhostSound() { UpdateGhostSound(); } public void SetGhostBlue(bool isBlue) { _ghostBlue = isBlue; UpdateGhostSound(); } public void SetGhostRetreat(bool isRetreating) { _ghostRetreating = isRetreating; UpdateGhostSound(); } public void StopAllSound() { audioSourcePacMan.Stop(); audioSourceGhosts.Stop(); // audioSourceExtraLife is not stopped on purpose, this sound is never interrupted } public void UpdatePelletCount(int pelletCount) { int level = 0; if (pelletCount < 16) { level = 4; } else if (pelletCount < 32) { level = 3; } else if (pelletCount < 64) { level = 2; } else if (pelletCount < 128) { level = 1; } // Debug.Log($"UpdatePelletCount: {pelletCount}, level: {level}"); if (_ghostSoundLevel >= level) { return; } _ghostSoundLevel = level; UpdateGhostSound(); } private void PlaySound(AudioSource audioSource, AudioClip audioClip, bool loop = false) { // Debug.Log($"PlaySound, audioSource: {audioSource}, audioClip: {audioClip}, loop: {loop}, suppress: {_suppress}"); if (_suppress) { return; } if (loop && audioSource.clip == audioClip && audioSource.isPlaying) { // Don't restart a looping sound return; } audioSource.clip = audioClip; audioSource.Play(); audioSource.loop = loop; } private void SwitchSound(AudioSource audioSource, AudioClip audioClip, bool loop) { if (_suppress) { return; } if (!audioSource.isPlaying || audioSource.clip == null) { PlaySound(audioSource, audioClip, loop); } if (audioSource.clip == audioClip) { // No need to switch return; } var newTimeSamples = (int)(audioSource.timeSamples / (double)audioSource.clip.samples * audioClip.samples); audioSource.clip = audioClip; audioSource.timeSamples = newTimeSamples; audioSource.Play(); } private void UpdateGhostSound() { if (_ghostRetreating) { PlaySound(audioSourceGhosts, pacGhostRetreat, true); _currentlyPlayingSiren = false; return; } if (_ghostBlue) { PlaySound(audioSourceGhosts, pacGhostBlue, true); _currentlyPlayingSiren = false; return; } var currentGhostLevelSound = GetSoundForGhostLevel(_ghostSoundLevel); if (_currentlyPlayingSiren) { SwitchSound(audioSourceGhosts, currentGhostLevelSound, true); } else { PlaySound(audioSourceGhosts, currentGhostLevelSound, true); } _currentlyPlayingSiren = true; } private AudioClip GetSoundForGhostLevel(int ghostLevel) { switch (ghostLevel) { case 1: return siren1; case 2: return siren2; case 3: return siren3; case 4: return siren4; default: return siren0; }; } }