Простой менеджер звуков в игре

Без музыки и звуков в игре не обойтись, за редким исключением. А конкретно, рассмотрим способ удобного воспроизведения различных звуковых эффектов и/или музыки. Главная задача, это удобство, поэтому мы исключим даже, казалось бы, такую удобную штуку, как массивы. То есть нам не потребуется ручками, куда-то там в скрипты запихивать каждый аудио файл. Всё что нужно, это создать необходимые папки и забросить в них соответствующие игровые ресурсы. Данный менеджер подойдет для озвучки, например, игрового интерфейса, меню, или какой-нибудь игры, типа головоломок, аркад и в общем там, где используется 2D звук.

Прежде всего, нужны сами звуки и музыка. Нужно создать в проекте папку Resources, а уже в ней разбить не группы, музыка или звуки, выглядеть это примерно так:

Простой менеджер звуков в игре

Закидываем туда необходимые OGG файлы.

Теперь на сцену добавим скрипт, который и будет загружать аудио из этих папок и воспроизводить его:

using UnityEngine;
using UnityEngine.Audio;
using System.Collections;

public class SoundManager : MonoBehaviour {

	public string mainFolder = "GameSounds";
	public string soundFolder = "Sounds";
	public string musicFolder = "Music";

	public float fadeSpeed = 3; // скорость плавного перехода между треками музыки

	public AudioMixerGroup musicGroup;
	public AudioMixerGroup soundGroup;

	private static SoundManager _instance;
	private static AudioSource last, current;
	private static float musicVolume, soundVolume;
	private static bool muteMusic, muteSound;

	void Awake()
	{
		musicVolume = 1;
		soundVolume = 1;
		_instance = this;
	}

	public static void SoundVolume(float volume)
	{
		soundVolume = volume;
	}

	public static void MusicVolume(float volume)
	{
		musicVolume = volume;
		if(current) current.volume = volume;
	}

	public static void MuteSound(bool value)
	{
		muteSound = value;
	}

	public static void MuteMusic(bool value)
	{
		muteMusic = value;
		if(current) current.mute = value;
	}

	void PlaySoundInternal(string soundName)
	{
		if(string.IsNullOrEmpty(soundName))
		{
			Debug.Log(_instance + " :: Имя файла не указанно.");
			return;
		}
			
		StartCoroutine(GetSound(soundName));
	}

	public static void PlaySound(string name)
	{
		_instance.PlaySoundInternal(name);
	}

	void PlayMusicInternal(string musicName, bool loop)
	{
		if(string.IsNullOrEmpty(musicName))
		{
			Debug.Log(_instance + " :: Имя файла не указанно.");
			return;
		}

		StartCoroutine(GetMusic(musicName, loop));
	}

	public static void PlayMusic(string name, bool loop)
	{
		_instance.PlayMusicInternal(name, loop);
	}

	void LateUpdate()
	{
		Fader();
	}

	void Fader()
	{
		if(last == null) return;

		last.volume = Mathf.Lerp(last.volume, 0, fadeSpeed * Time.deltaTime);
		current.volume = Mathf.Lerp(current.volume, musicVolume, fadeSpeed * Time.deltaTime);

		if(last.volume < 0.05f)
		{
			last.volume = 0;
			Destroy(last.gameObject);
		}
	}

	IEnumerator GetMusic(string musicName, bool loop)
	{
		ResourceRequest request = LoadAsync(musicFolder + "/" + musicName);

		while(!request.isDone)
		{
			yield return null;
		}

		AudioClip clip = (AudioClip)request.asset;

		if(clip == null)
		{
			Debug.Log(_instance + " :: Файл не найден: " + musicName);
			return false;
		}

		last = current;

		GameObject obj = new GameObject("Music: " + musicName);
		AudioSource au = obj.AddComponent<AudioSource>();
		obj.transform.parent = transform;
		au.outputAudioMixerGroup = musicGroup;
		au.playOnAwake = false;
		au.loop = loop;
		au.mute = muteMusic;
		au.volume = (last == null) ? musicVolume : 0;
		au.clip = clip;
		au.Play();
		current = au;
	}

	IEnumerator GetSound(string soundName)
	{
		ResourceRequest request = LoadAsync(soundFolder + "/" + soundName);

		while(!request.isDone)
		{
			yield return null;
		}

		AudioClip clip = (AudioClip)request.asset;

		if(clip == null)
		{
			Debug.Log(_instance + " :: Файл не найден: " + soundName);
			return false;
		}

		GameObject obj = new GameObject("Sound: " + soundName);
		AudioSource au = obj.AddComponent<AudioSource>();
		obj.transform.parent = transform;
		au.outputAudioMixerGroup = soundGroup;
		au.playOnAwake = false;
		au.loop = false;
		au.mute = muteSound;
		au.volume = soundVolume;
		au.clip = clip;
		au.Play();
		Destroy(obj, clip.length);
	}

	ResourceRequest LoadAsync(string name)
	{
		string path = mainFolder + "/" + name;
		return Resources.LoadAsync<AudioClip>(path);
	}
}

Итак, когда мы запрашиваем звук по имени файла, скрипт ищет его в соответствующей папке, загружает, затем создается новый объект, к нему добавляется AudioSource, которому в свою очередь, назначается загруженный файл. После чего, воспроизводится.

Если мы запрашиваем звук, то он будет автоматически уничтожен, после того как воспроизведение закончится.

Если мы запрашиваем музыку, то она будет воспроизводиться в зацикленном режиме (есть опция это отключить), далее, если музыка играет и мы запрашиваем другой файл музыки, в этом случаи, будет произведен плавный переход, с одного трека на другой.

Теперь создадим скрипт запросов, который можно цеплять на кнопки, слайдеры и т.п. элементы UI:

using UnityEngine;
using System.Collections;

public class SoundManagerComponent : MonoBehaviour {

	public void PlayMusic(string name)
	{
		SoundManager.PlayMusic(name, true);
	}

	public void PlaySound(string name)
	{
		SoundManager.PlaySound(name);
	}

	public void SoundVolume(float volume)
	{
		SoundManager.SoundVolume(volume);
	}

	public void MusicVolume(float volume)
	{
		SoundManager.MusicVolume(volume);
	}

	public void ToggleMusicMuted(bool value)
	{
		SoundManager.MuteMusic(!value);
	}

	public void ToggleSoundMuted(bool value)
	{
		SoundManager.MuteSound(!value);
	}
}

Скрипт для ручного добавления события, например, кнопка:


Как следует из примера, тут мы просто указали функцию запроса музыки и имя файла. Всё просто.

Скачать демо проект:

Внимание! Посетители, находящиеся в группе Гости, не могут скачивать файлы.
Информация
Посетители, находящиеся в группе Гости, не могут оставлять комментарии к данной публикации.
  • Яндекс.Метрика