В этом уроке я покажу, как воспроизвести аудиофайл в Unity и, что более важно, как я решил проблему, связанную с наложением звука при воспроизведении через Audio Source.
Видеоверсия этого руководства в настоящее время недоступна на этом языке.
Текстовая расшифровка видео
Всем привет! В этом уроке я покажу, как воспроизвести аудиофайл в Unity и, что более важно, как я решил проблему, связанную с наложением звука при воспроизведении через Audio Source. Прежде чем продолжить, отмечу, что решение, представленное в видео, является лишь тем вариантом, который я использовал для этой задачи. Вероятно, существуют и другие, возможно даже более удачные способы, поэтому не воспринимайте показанный здесь подход как единственно правильный.
Урок создан с использованием Unity 2022. В частности, я хочу воспроизводить звук шагов при движении персонажа по сцене. Этот аудиофайл взят из первой игры Prince of Persia, созданной Jordan Mechner. Это была моя первая игра на ПК. Задача может показаться простой, однако, как мы увидим, в ней скрыта небольшая сложность.
Чтобы воспроизвести звук шагов, сначала нужно добавить объект Audio Source к персонажу. В этом компоненте мы укажем конкретный аудиофайл для воспроизведения и настроим другие параметры.
Audio Source — это компонент, который добавляется к объекту на сцене. Это может быть персонаж, дверь, мяч или даже невидимый объект, что полезно, например, для воспроизведения звука, когда персонаж входит в определённую комнату или приближается к какому-либо предмету.
Чтобы звук был слышен через Main Camera, у камеры должен быть активный компонент Audio Listener. В новых проектах Unity Main Camera обычно уже содержит активный Audio Listener, поскольку предполагается, что пользователь будет использовать звук. Если Audio Listener отсутствует, его можно добавить через Inspector объекта Main Camera.

В моём случае аудиофайл должен быть связан с персонажем.
В проекте есть объект Player, который является родительским для Main Camera. Скрипт движения связан с объектом Player, а на камере установлен скрипт, позволяющий осматриваться. Поэтому компонент AudioSource я добавлю к объекту Player.

Открыв вкладку только что добавленного компонента, вы сразу увидите поле AudioClip, которое по умолчанию установлено в значение None.
Также есть флажок Play on Awake, который включён по умолчанию. Эта опция запускает воспроизведение аудиофайла при старте игры. В некоторых случаях это полезно, но для нашей задачи не требуется, поэтому я сниму этот флажок.

Импортировать аудиоклип в проект очень просто. Нужно перетащить файл из окна File Browser во вкладку Project или выбрать его на диске через меню Assets - Import New Asset.

Unity поддерживает различные аудиоформаты, например mp3, и отображает рядом с файлом значок в виде ноты во вкладке Project.
Как видите, в моём проекте уже есть несколько аудиофайлов, предназначенных для воспроизведения в разные моменты. Среди них нас интересует файл PoP---walk.
Чтобы продолжить, я сначала выбираю объект Player в Hierarchy.
Затем нажимаю и удерживаю кнопку мыши на ресурсе PoP---walk во вкладке Project.

После этого перетаскиваю этот файл в поле AudioClip компонента AudioSource, связанного с Player.
Как уже упоминалось, звук должен воспроизводиться при движении персонажа.
Для этого я открою скрипт, отвечающий за движение, и добавлю необходимый код.
Сначала создаю переменную типа AudioSource и инициализирую её в функции Start, связав с компонентом AudioSource объекта Player.
Для этого я пишу следующий код:
private AudioSource playerAudioSource;
и внутри функции Start:
playerAudioSource = GetComponent();
Также необходимо создать переменную типа AudioClip для связи с аудиофайлом, который должен воспроизводиться. Я назову её myAudioClip и использую атрибут SerializeField, чтобы поле отображалось в Inspector. После сохранения файла скрипта следующим шагом будет перетащить ресурс PoP---Walk в поле myAudioClip скрипта через Inspector.
Сразу после объявления playerAudioSource я добавляю следующую строку кода:
[SerializeField] private AudioClip myAudioClip;

После сохранения скрипта возвращаюсь в Unity Editor и перетаскиваю ресурс PoP---Walk в поле myAudioClip скрипта, как описано ранее.

На данный момент звук ещё не воспроизводится.
В функции Update скрипта уже есть инструкции для отслеживания нажатий клавиш, управляющих движением персонажа.
Когда пользователь перемещает персонажа, значение Input.GetAxis для Horizontal и Vertical, которые я для удобства переименовал в x и y, может быть равно -1 или 1 в зависимости от направления.
В этом случае можно было бы написать следующий код:
if ((Mathf.Abs(x) == 1) || (Mathf.Abs(z) == 1))
playerAudioSource.PlayOneShot(myAudioClip);

и попробовать запустить игру. Однако это было бы серьёзной ошибкой, потому что Unity воспроизводил бы аудиофайл на КАЖДОМ КАДРЕ ИГРЫ.
Ситуация не улучшается, если просто переместить вызов PlayOneShot внутрь Coroutine и добавить задержку в одну секунду с помощью yield return new WaitForSeconds(1). Проблема остаётся, так как Update будет запускать Coroutine на каждом кадре, что приведёт к той же ошибке.
Следовательно, Coroutine не нужен. Вместо этого требуется простая проверка состояния AudioSource. Воспроизводить звук нужно только в том случае, если AudioSource в данный момент его не воспроизводит.
Это можно сделать внутри функции Update, добавив в блок if, проверяющий значения x и y, следующий код:
if (!(playerAudioSource.isPlaying))
playerAudioSource.PlayOneShot(myAudioClip);

Теперь можно сохранить скрипт, запустить игру и оценить, точнее услышать, результат.
Перед завершением урока хочу поделиться ещё одной мыслью. Поле AudioClip компонента AudioSource можно изменять через скрипт.
Это означает, что можно использовать один и тот же AudioSource для стандартного звука шагов, а во время игры заменять аудиоклип, например, если персонаж идёт по гравию, по берегу моря или по другой поверхности, которую можно определить с помощью Colliders.
Кроме того, если персонаж умеет летать, можно отключить AudioSource, чтобы звук не воспроизводился.
На этом всё. Надеюсь, урок оказался полезным. До встречи!