Sound System
Overview
SoundManager handles all audio in the game - music, sound effects, and user preferences.
What's Included
Sound Effects
- 🎵 Shape grab
- 🎯 Shape place
- ✨ Line clear
- 🔥 Combo sounds
- ❌ Invalid placement
- 🎊 Game over
Music
- 🎼 Background music (loop)
- 🎶 Menu music (optional)
SoundManager Component
Inspector Settings
┌─ SoundManager ──────────────────┐
│ Music Volume: 0.7 │
│ SFX Volume: 1.0 │
│ │
│ Background Music: [AudioClip] │
│ │
│ Sound Effects: │
│ Grab: [AudioClip] │
│ Place: [AudioClip] │
│ Clear: [AudioClip] │
│ Combo: [AudioClip] │
│ Invalid: [AudioClip] │
│ GameOver: [AudioClip] │
└──────────────────────────────────┘
How to Use
Playing Sounds
// From any script:
SoundManager.Instance.PlayGrab();
SoundManager.Instance.PlayPlace();
SoundManager.Instance.PlayClear();
SoundManager.Instance.PlayCombo();
SoundManager.Instance.PlayInvalid();
SoundManager.Instance.PlayGameOver();
Controlling Volume
// Music volume (0.0 - 1.0)
SoundManager.Instance.SetMusicVolume(0.5f);
// SFX volume (0.0 - 1.0)
SoundManager.Instance.SetSFXVolume(1.0f);
Muting
// Mute/unmute music
SoundManager.Instance.MuteMusic(true);
// Mute/unmute SFX
SoundManager.Instance.MuteSFX(true);
Audio Sources
SoundManager uses multiple AudioSources:
SoundManager GameObject
├── MusicSource (AudioSource)
│ └── Loops: Yes
│ └── Volume: musicVolume
│
└── SFXSource (AudioSource)
└── Loops: No
└── Volume: sfxVolume
Singleton Pattern
public static SoundManager Instance { get; private set; }
void Awake()
{
if (Instance != null && Instance != this)
{
Destroy(gameObject);
return;
}
Instance = this;
DontDestroyOnLoad(gameObject);
}
One instance, persists across scenes.
Integration Examples
Shape Dragging
// In NewDraggableShape.cs
public void OnBeginDrag(PointerEventData data)
{
SoundManager.Instance.PlayGrab();
// ... dragging logic
}
public void OnEndDrag(PointerEventData data)
{
if (validPlacement)
{
SoundManager.Instance.PlayPlace();
}
else
{
SoundManager.Instance.PlayInvalid();
}
}
Line Clearing
// In NewManager.cs
void OnLinesCleared(int count)
{
if (count > 0)
{
SoundManager.Instance.PlayClear();
}
}
Combo System
// In NewScoreManager.cs
void OnComboIncreased(int combo)
{
if (combo > 1)
{
SoundManager.Instance.PlayCombo();
}
}
Settings UI
Creating Volume Sliders
public class AudioSettings : MonoBehaviour
{
[SerializeField] private Slider musicSlider;
[SerializeField] private Slider sfxSlider;
void Start()
{
// Load saved volumes
musicSlider.value = PlayerPrefs.GetFloat("MusicVolume", 0.7f);
sfxSlider.value = PlayerPrefs.GetFloat("SFXVolume", 1.0f);
// Apply saved settings
SoundManager.Instance.SetMusicVolume(musicSlider.value);
SoundManager.Instance.SetSFXVolume(sfxSlider.value);
// Listen for changes
musicSlider.onValueChanged.AddListener(OnMusicVolumeChanged);
sfxSlider.onValueChanged.AddListener(OnSFXVolumeChanged);
}
void OnMusicVolumeChanged(float value)
{
SoundManager.Instance.SetMusicVolume(value);
PlayerPrefs.SetFloat("MusicVolume", value);
}
void OnSFXVolumeChanged(float value)
{
SoundManager.Instance.SetSFXVolume(value);
PlayerPrefs.SetFloat("SFXVolume", value);
}
}
Mute Buttons
public class MuteButton : MonoBehaviour
{
[SerializeField] private Image icon;
[SerializeField] private Sprite mutedIcon;
[SerializeField] private Sprite unmutedIcon;
private bool isMuted;
public void ToggleMute()
{
isMuted = !isMuted;
SoundManager.Instance.MuteSFX(isMuted);
icon.sprite = isMuted ? mutedIcon : unmutedIcon;
}
}
Audio Clip Recommendations
File Formats
- ✅ WAV - High quality, larger size
- ✅ OGG - Good quality, smaller size (recommended)
- ❌ MP3 - Not recommended (licensing issues)
Clip Lengths
- SFX: 0.1 - 0.5 seconds (short!)
- Music: 1-3 minutes (loops)
Sample Rates
- SFX: 22050 Hz (sufficient)
- Music: 44100 Hz (better quality)
Advanced Features
Pitch Variation
Make sounds less repetitive:
public void PlayPlace()
{
sfxSource.pitch = Random.Range(0.95f, 1.05f);
sfxSource.PlayOneShot(placeClip);
sfxSource.pitch = 1f; // Reset
}
Sound Pools
For frequently played sounds:
private AudioSource[] sfxPool;
void Awake()
{
sfxPool = new AudioSource[5];
for (int i = 0; i < 5; i++)
{
GameObject obj = new GameObject($"SFX_{i}");
obj.transform.parent = transform;
sfxPool[i] = obj.AddComponent<AudioSource>();
}
}
public void PlaySFX(AudioClip clip)
{
AudioSource available = Array.Find(sfxPool, s => !s.isPlaying);
if (available != null)
{
available.PlayOneShot(clip);
}
}
Fade In/Out
public void FadeOutMusic(float duration)
{
StartCoroutine(FadeOutCoroutine(duration));
}
IEnumerator FadeOutCoroutine(float duration)
{
float startVolume = musicSource.volume;
float elapsed = 0f;
while (elapsed < duration)
{
elapsed += Time.deltaTime;
musicSource.volume = Mathf.Lerp(startVolume, 0f, elapsed / duration);
yield return null;
}
musicSource.Stop();
musicSource.volume = startVolume;
}
Distance-Based Volume
If you add 3D audio later:
public void PlaySFXAt(Vector3 position, AudioClip clip)
{
AudioSource.PlayClipAtPoint(clip, position, sfxVolume);
}
Audio Mixer (Optional Enhancement)
For more control, add an Audio Mixer:
1. Create Audio Mixer Asset
2. Add groups: Master, Music, SFX
3. Assign AudioSources to groups
4. Control with code:
audioMixer.SetFloat("MusicVolume", Mathf.Log10(volume) * 20);
Mobile Considerations
Audio Settings
// On mobile, lower music volume by default
#if UNITY_ANDROID || UNITY_IOS
float defaultMusicVolume = 0.5f;
#else
float defaultMusicVolume = 0.7f;
#endif
Background Audio
void OnApplicationPause(bool paused)
{
if (paused)
{
musicSource.Pause();
}
else
{
musicSource.UnPause();
}
}
Performance Tips
DO:
✅ Use compressed audio (OGG) ✅ Load clips in Inspector (faster) ✅ Use AudioSource pooling ✅ Set appropriate quality settings
DON'T:
❌ Load clips at runtime ❌ Use very high sample rates ❌ Play too many sounds at once ❌ Forget to stop unused sources
Debugging
void Update()
{
if (Input.GetKeyDown(KeyCode.M))
{
Debug.Log($"Music: {musicSource.isPlaying}, " +
$"Volume: {musicSource.volume}");
}
}
Common Issues
Sound not playing
- ✅ Check clip is assigned
- ✅ Check volume > 0
- ✅ Check AudioSource exists
- ✅ Check not muted
Sound cutting off
- ✅ Use PlayOneShot for overlapping
- ✅ Use audio source pool
- ✅ Don't reuse same source too fast
Music not looping
- ✅ Check "Loop" checkbox on AudioSource
- ✅ Verify clip is assigned
What's Next?
- 📱 Ads System - monetization
- 🎨 Animations - visual feedback
- ⚙️ Customization - tune your game
Audio Tip
Good audio = 50% of game feel! Don't skip sound effects. Even simple blips make huge difference!