Как добавить звуки шагов в юнити

от admin

Добавление звуков ходьбы в Unity

Как известно, любое действие в игре сопровождается звуковыми эффектами. И звуки при движении игрока не исключение. В данной статье мы научимся добавлять звуки при ходьбе персонажа.

Мы не будем рассматривать реализацию самой ходьбы, а рассмотрим только воспроизведение звука ходьбы, в момент ходьбы. Но если по какой-либо причине Вы ещё не создали в своей игре движение игрока, то сначала предлагаем изучить гайд по реализации движения персонажа.

А теперь перейдём непосредственно к теме данной статьи. Для начала нам необходимо скачать звук ходьбы в интернете, и перетащить этот аудиофайл в окно Project. Так же можете переименовать данный файл на своё усмотрение. У меня он переименован в run.

Теперь для нашего персонажа создадим компонент Audio Source, который нужен для хранения и воспроизведения нашего аудиофайла шагов. После создания данного компонента, обратим своё внимание на три важных поля:

В поле AudioClip перетащите свой аудиофайл шагов из окна Project. В поле Play On Awake необходимо убрать галочку, чтобы наши шаги не воспроизводились сразу же, после запуска игры. Мы их сами будем воспроизводить в скрипте. А в поле Loop необходимо галочку всё же поставить, чтобы по завершению звукового файла, он воспроизводился снова и снова.

Остался последний штрих. Нам необходимо с помощью кода воспроизводить звук шагов, которые подгружены в компонент Audio Source в тот момент, когда персонаж идёт, и останавливать этот звук, когда персонаж не идёт. Для этого создадим новый скрипт C# с названием SoundRun, в котором пропишем следующее:

В первой строке мы объявили переменную moveSound, в которой будет храниться ссылка на компонент AudioSource. Поэтому не забудьте в окне Inspector перетащить компонент Audio Source в поле moveSound.

В строке #9 мы проверяем, нажата ли кнопка движения игрока в одну из сторон: вправо, влево, вверх, вниз. И если да, то с помоью метода Play() воспроизводим наш аудиофайл шагов. А если кнопка движения не нажата, то принудительно останавливаем звук шагов с помощью метода Stop().

Так же обратите внимание, что в строке #11 у нас есть ещё одна проверка на то, воспроизводится ли звук шагов в данный момент? Если да, то ничего не делаем, поскольку так и надо. А если нет, то начинаем воспроизведение звука.

Важно: Чтобы не создавать множество скриптов, Вы можете скрипт SoundRun не создавать, а скопировать данный код в ваш скрипт, который отвечает за передвижение персонажа. Так будет более правильно.

Если после данной статьи, Вы захотели пойти дальше, и реализовать звук стрельбы, то это делается немного по другому, чем реализация звуков шагов. Спешу Вас обрадовать, это делается на много проще. О том, как добавить звук стрельбы в игру, мы писали в отдельной статье. Так что рекомендуем к прочтению.

На этом всё. Если остались вопросы, пишите в комментариях. А так же не забываем ставить алйки 🙂

Как сделать звуки шагов? [FPS]

Грамотное звуковое оформление в игре, может вытянуть всю атмосферу. Простенький менеджер звуков мы уже разбирали, ищите его где-то тут неподалеку. На этот раз затронем тему озвучки шагов персонажа. Проект ориентирован на игру от первого лица, когда ног персонажа не видно, то есть, звук не привязан к анимации. Впрочем, есть отдельный класс, который отвечает за воспроизведение звуков, поэтому при желании можно сделать привязку к анимации ног, что применимо и для двухмерной игрушки. В нашем же случаи, мы рассмотрим настройку интервала шагов в вручную. Кроме того, в комплекте идет и расширенный скрипт управления, так как он работает в связке со скриптом звуков.

Для работы нам понадобится условная моделька персонажа. Сделать ее достаточно просто. На пустой объект вешаем капсульный коллайдер, затем удочеряем камеру, поднимаем на уровень головы и всё.

Далее, в проекте должна быть папка Resources. В ней у нас будут хранится звуки. Мы будем использовать загрузку массивов на старте сцены, потому как в процессе разработки, звуки могут меняться, можем добавлять новые или же удалять ненужные. И чтобы каждый раз не мучится с ручным заполнением массива, лучше делать это через скрипт в таких случаях.

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

Здесь есть меню, для выбора определенных звуков. Меню можно конечно расширить, если это нужно.

Создаем скрипт управления:

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

Простая звуковая система для FPSController в Unity

Ученики нашей школы часто спрашивали, как добавить систему звуков, как работать со звуками и т.д. Поэтому мы решили подготовить краткий но понятный материал по этой теме.

В FPSController’е уже встроен звук шагов, прыжка и приземления. Тем не менее, в реальной ситуации, эту систему приходится переделывать. Например, для сетевой игры, чтобы точно синхронизировать звук шагов, или, если хочется добавить какой-либо функционал, например, разный звук при ходьбе по разным материалам. В этой статье мы покажем вам, как отключить стандартную систему звука, а затем, как сделать простой вариант системы звуков, с одним звуковым файлом для шагов.

Подготовка сцены

Для начала нужно подготовить сцену.

  1. FPSController

Скачиваем с Asset Store. Открываем окно Asset Store’а.

Вбиваем в поиск «Standart Assets».

Кликаем «Download», ждем пока скачается, потом кликаем «Import».

Возможно будут ошибки импорта, т.к. Standart Assets обновляется каждый раз при выходе новой версии.

Не боимся, просто очищаем консоль.

Чтобы очистить консоль:

– Кликаем снизу на текст ошибки

– В открывшемся окне кликаем на «Clear»

  1. Создаем

Меняем масштаб X и Z 100х100

  1. Делаем материал для «земли»

Это не обязательно, когда «земля» белая, немного засвечивает экран, не очень приятно.

Чтобы создать и присвоить материал:

  1. Правый клик на Assets
  2. Create -> Material
  3. Выбираем его и перетаскиваем на «землю»
  4. Меняем настройки цвета, как нравится

Мы сделали цвет чуть потемнее

  1. Находим в Assets\Standard Assets\Characters\FirstPersonCharacter\Prefabs префаб (обозначется синеньким кубиком) FPSController и перетаскиваем его на сцену.

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

  1. Ставим кубик, чтобы ходить вокруг него
  2. Удаляем Main Camera, которая есть по стандарту на сцене
  3. Пробуем

  1. Отключаем Use FOV Kick и Use Blob Head в FirstPersonCharacter, но это не обязательно
  2. Чтобы убрать звуки шагов: В Скрипте FirstPersonController.cs с помощью символов «//»
    1. Комментируем строку 74
    2. Комментируем строку 119
    3. Комментируем строку 130

    Пример закоменченной строки:

    Система звуков отключена, всё готово, чтобы делать свою систему.

    Подготовка скрипта

    1. Качаем звуки, можно с сайта premiumbeat.com/blog/40-free-footstep-foley-sound-effects/
    1. Создаем папку Sounds в Assets
    2. Распаковываем архив в папку Sounds

    Импорт займет много времени – звуковые файлы гарантированно долго конвертируются.

    1. Создаем папку Scripts
    2. Создаем скрипт FootstepsSoundController
    3. Добавляем скрипт cs на FPSController на сцене
    4. Когда объявили переменные – не забудьте добавить аудиоклипы через инспектор:

    Звук прыжка и приземления берем из стандартных ассетов, в папке FirstPersonCharacter

    Звук ходьбы берем на ваше усмотрение из заранее заготовленных, из папки Sounds. Мы выбрали Concrete_Shoes_Running.

    Должно получится так:

    Скриптинг

    Обратите внимание на комментарии в коде. Больше инфы после листинга кода.

    public class FootstepsSoundController : MonoBehaviour

    public AudioClip FootstepsSound;

    public AudioClip JumpSound;

    public AudioClip LandingSound;

    private AudioSource audioSource;

    private CharacterController cController;

    private bool wasGrounded = false ;

    //getcomponent очень требователен к ресурсам компьютера, поэтому мы выполняем его один раз, “сохраняем ссылки” на компоненты

    if (cController.isGrounded) // персонаж на земле

    if (cController.velocity.sqrMagnitude > 0f) // персонаж двигается , используется квадратичная магнитуда ,

    //т.к. это операция менее требовательна к ресурсам, и нам не нужна точная скорость – нам нужен сам факт передвижения

    else // персонаж НЕ двигается

    if (audioSource.clip != JumpSound && audioSource.clip != LandingSound) // если аудиоклип в AudioSorce это не клип прыжка и не клип приземление

    if (audioSource.isPlaying) // если звук проигрывается

    audioSource.Stop(); // выключаем проигрывание звуков

    if ( cController . isGrounded != wasGrounded ) //проигрываем звук, если раньше персонаж был на земле, а теперь в воздухе

    wasGrounded = true ; //запоминаем прошлое состояние персонажа – в данном случае персонаж на земле

    else //персонаж Н E на земле

    if (audioSource.clip != JumpSound && audioSource.clip != LandingSound ) //если аудиоклип в AudioSorce это не клип прыжка и не клип приземление

    if ( audioSource . isPlaying ) //если звук проигрывается

    audioSource . Stop (); //выключаем проигрывание звуков

    if (cController.isGrounded != wasGrounded) //проигрываем звук, если раньше персонаж был в воздухе, а теперь на земле

    wasGrounded = false ; //запоминаем прошлое состояние персонажа – в данном случае персонаж в воздухе

    Подробнее

    1. Зачем вообще нужен GetComponent?

    На сцене может существовать сколько угодно AudioSource и CharacterController. С помощью GetComponent мы указываем какой именно компонент мы используем.

    1. Почему GetComponent в старте? почему логика в FixedUpdate, а не в Update?
      1. Функция GetComponent очень требовательна к ресурсам. Мы выполняем её только один раз при запуске скрипта и сохраняем результат её работы в виде ссылки на компонент. Дальше мы можем использовать ссылку на компонент на свое усмотрение, без повторного использования GetComponent.
      2. Звук может проигрываться в любой момент, и, вроде логично было бы выполнять функцию в Update. Но на деле обновление положения физических объектов (в т.ч. CharacterController’а) происходит каждый FixedUpdate. То есть, если выполнять логику скрипта в Update, то, на деле, мы просто сильнее загрузим компьютер, а результат будет точно такой же.
      1. Чтобы добавить ваш аудиоклип в скрипт создаем переменную тип AudioClip.
      2. В AudioSource, переменную clip, присваиваем ваш аудиоклип
      3. Чтобы начать проигрывание звук – используем команду Play(), чтобы остановить проигрывания звука – используем команду Stop().

      Пример:

      4. Условия выполнения логики скрипта

      • Если персонаж на земле И двигается – включаем звук шагов
      • Если персонаж в воздухе ИЛИ НЕ двигается – выключаем звук шагов
      • Если персонаж был в воздухе, а потом оказался на земле – проигрываем звук приземления
      • Если персонаж был на земле, а потом оказался в воздухе – проигрываем звук прыжка

      5. Магнитуда вектора – это длина вектора. Зачем? Скорость это трехкомпонентный вектор (X,Y,Z). Его длинна – скорость в метрах/секунду. В нашем случае нам просто нужно узнать двигается ли персонаж, т.е. если магнитуда вектора скорости больше нуля – то персонаж двигается.

      Заключение

      Многие разработчики недооценивают важность звука в видеоиграх. Так же, системы звука всегда очень сложные, требуют много работы не только с кодом, но и с звуковыми файлами.

      Но, на деле, именно правильное звуковое сопровождение создает эффект «присутствия» и «погружения» в игру, а это, как известно, очень важно.

      Туториал 4: 2Д платформер (для новичков). Часть 1.

      void FixedUpdate () <
      //декларация переменной с её инициализацией значением полученным с горизонтальной оси (значение лежит в области между -1 и 1)
      float x = Input.GetAxis ( «Horizontal» );
      //декларация локального вектора и инициализация посчитанным значением
      //x: значение от InputManager * speed
      //y: принять текущее значение, мы не будем его менять, из-за использования силы тяжести
      //z: должно быть равно нулю, нам не нужно движение по оси Z
      Vector3 move = new Vector3 (x * speed, rb.velocity.y, 0f );
      //Изменить скорость игрока на вычисленный вектор
      rb.velocity = move;
      >
      >

      5. Step

      using System.Collections;
      using System.Collections.Generic;
      using UnityEngine;

      public class PlayerMove : MonoBehaviour <

      //в инспекторе мы можем выбрать, какие слои будут землёй
      public LayerMask whatIsGround;
      //позиция для проверки касания земли
      public Transform groundCheck;
      //переменная, которая будет true, если крыса находится на земле
      public bool isGrounded;
      //значение величины силы
      public float jumpForce;
      //переменная для скорости движения
      public float speed;
      //ссылочная переменная для компонента Rigidbody2D
      Rigidbody2D rb;

      void Start () <
      //делаем ссылку на Rigidbody2D
      rb = GetComponent < Rigidbody2D > ();
      >

      //я буду использовать Update() для более точного определения прыжка
      void Update () <
      //проверка, нажат-ли прыжок и находится-ли крыса на земле
      if ( Input .GetButtonDown ( «Jump» ) && isGrounded) <
      //применяем силу на Rigidbody2D вдоль оси Y для прыжка
      rb.AddForce ( Vector2 .up * jumpForce, ForceMode2D .Impulse);
      //переключаем переменную, чтобы предотвратить следующий прыжок, или мы могли бы снова прыгнуть (до того, как isGrounded будет переключена в FixedUpdate ())
      isGrounded = false;
      >
      >

      void FixedUpdate () <
      //изменяем переменную, зависящую от результата Physics2D.OverlapPoint
      isGrounded = Physics2D .OverlapPoint (groundCheck.position, whatIsGround);
      //декларация переменной с её инициализацией значением полученным с горизонтальной оси (значение лежит в области между -1 и 1)
      float x = Input.GetAxis ( «Horizontal» );
      //декларация локального вектора и инициализация посчитанным значением
      //x: значение от InputManager * speed
      //y: принять текущее значение, мы не будем его менять, из-за использования силы тяжести
      //z: должно быть равно нулю, нам не нужно движение по оси Z
      Vector3 move = new Vector3 (x * speed, rb.velocity.y, 0f );
      //Изменить скорость игрока на вычисленный вектор
      rb.velocity = move;
      >
      >

      6. Step

      using System.Collections;
      using System.Collections.Generic;
      using UnityEngine;

      public class PlayerMove : MonoBehaviour <

      //в инспекторе мы можем выбрать, какие слои будут землёй
      public LayerMask whatIsGround;
      //позиция для проверки касания земли
      public Transform groundCheck;
      //переменная, которая будет true, если крыса находится на земле
      public bool isGrounded;
      //значение величины силы
      public float jumpForce;
      //переменная для скорости движения
      public float speed;
      //ссылочная переменная для компонента Rigidbody2D
      Rigidbody2D rb;
      //переменная контроля направления крысы
      public bool isLookingLeft;

      void Start () <
      //делаем ссылку на Rigidbody2D
      rb = GetComponent < Rigidbody2D > ();
      >

      //я буду использовать Update() для более точного определения прыжка
      void Update () <
      //проверка, нажат-ли прыжок и находится-ли крыса на земле
      if ( Input .GetButtonDown ( «Jump» ) && isGrounded) <
      //применяем силу на Rigidbody2D вдоль оси Y для прыжка
      rb.AddForce ( Vector2 .up * jumpForce, ForceMode2D .Impulse);
      //sпереключаем переменную, чтобы предотвратить следующий прыжок, или мы могли бы снова прыгнуть (до того, как isGrounded будет переключена в FixedUpdate ())
      isGrounded = false;
      >
      >

      void FixedUpdate () <
      //изменяем переменную, зависит от результата Physics2D.OverlapPoint
      isGrounded = Physics2D .OverlapPoint (groundCheck.position, whatIsGround);
      //декларация переменной с её инициализацией значением полученным с горизонтальной оси (значение лежит в области между -1 и 1)
      float x = Input.GetAxis ( «Horizontal» );
      //декларация локального вектора и инициализация посчитанным значением
      //x: значение от InputManager * speed
      //: принять текущее значение, мы не будем его менять, из-за использования силы тяжести
      //z: должно быть равно нулю, нам не нужно движение по оси Z
      Vector3 move = new Vector3 (x * speed, rb.velocity.y, 0f );
      //изменить скорость игрока на вычисленный вектор
      rb.velocity = move;
      //проверка, совпадает ли направление взгляда с направлением движения
      if (x < 0 && !isLookingLeft)
      //вызов функции поворота крысы, если проверка совпала
      TurnTheRat ();
      //проверка, совпадает ли направление взгляда с направлением движения
      if (x > 0 && isLookingLeft)
      //вызов функции поворота крысы, если проверка совпала
      TurnTheRat ();
      >

      //функция поворота крысы
      void TurnTheRat ()
      <
      //смена переменной показывающей направление взгляда на обратное значение
      isLookingLeft = !isLookingLeft;
      //поворот крысы через инвертацию размера по оси х
      transform.localScale = new Vector3 (transform.localScale.x * -1 , transform.localScale.y, transform.localScale.z);
      >

      7. Step

      8. Шаг

      9. Шаг

      using System.Collections;
      using System.Collections.Generic;
      using UnityEngine;

      public class PlayerAnim : MonoBehaviour <

      //ссылочная переменная для аниматора
      Animator anim;
      //ссылочная переменная для rigidbody2D
      Rigidbody2D rb;

      void Start () <
      //делаем ссылку на аниматор
      anim = GetComponent < Animator > ();
      //делаем ссылку на Rigidbody2D
      rb = GetComponent < Rigidbody2D > ();
      >

      void Update () <
      //меняем параметр speed в Animator. Используем значение скорости по оси х
      anim.SetFloat ( «speed» , Mathf .Abs (rb.velocity.x));
      >
      >

      10. Шаг

      11. Шаг

      12. Шаг

      using System.Collections;
      using System.Collections.Generic;
      using UnityEngine;

      public class PlayerAnim : MonoBehaviour <

      //ссылочная переменная для аниматора
      Animator anim;
      //ссылочная переменная для rigidbody2D
      Rigidbody2D rb;
      //ссылочная переменная для PlayerMove
      PlayerMove pm;

      void Start () <
      //делаем ссылку на Animator
      anim = GetComponent < Animator > ();
      //делаем ссылку на Rigidbody2D
      rb = GetComponent < Rigidbody2D > ();
      //делаем ссылку на PlayerMove
      pm = GetComponent < PlayerMove > ();
      >

      void Update () <
      //проверка, находится ли крыса на земле
      if (pm.isGrounded) <
      //меняем параметр isJumping на false
      anim.SetBool ( «isJumping» , false );
      //меняем параметр speed. Используем абсолютное значение вектора скорости по х
      anim.SetFloat ( «speed» , Mathf .Abs (rb.velocity.x));
      // если крыса не на земле
      > else <
      //меняем параметр speed на 0
      anim.SetFloat ( «speed» , 0 );
      //меняем параметр isJumping на true
      anim.SetBool ( «isJumping» , true );
      >
      >

      13. Step

      using System.Collections;
      using System.Collections.Generic;
      using UnityEngine;

      public class PlayerSound : MonoBehaviour <

      //ссылочная переменная для звукового файла
      public AudioClip footsteps;

      //публичная функция, получим доступ к ней из аниматора
      public void FootStepsAudio () <
      //воспроизвести заданный звук на позиции крысы
      AudioSource .PlayClipAtPoint (footsteps, transform.position);
      >
      >

      14. Шаг

      using System.Collections;
      using System.Collections.Generic;
      using UnityEngine;

      public class PlayerSound : MonoBehaviour <

      //ссылочная переменная для аудио-файла
      public AudioClip footsteps;

      //публичная функция, получим доступ к ней из аниматора
      public void FootStepsAudio () <
      //воспроизвести заданный звук на позиции крысы
      AudioSource .PlayClipAtPoint (footsteps, transform.position);
      >

      //запустится если было касание другого Collider2D
      void OnCollisionEnter2D ( Collision2D coll) <
      //проверка тэга на тэг «Ground»
      if (coll.gameObject.tag == «Ground» ) <
      //воспроизвести заданный звук на позиции крысы
      AudioSource .PlayClipAtPoint (footsteps, transform.position);
      >
      >

      15. Шаг

      Выберите Ground в иерархии. Создайте prefab Ground (перетащите объект в Assets). Поместите prefab Ground в сцену, как следующую платформу.

      Выберите Main Camera и сделайте её дочерним объектом Rat (перетащите Main Camera на Rat). Камера будет следовать за крысой.

      Можете изменить X-position камеры на 0, чтобы убрать рывки при повороте.
      Я думаю, этого достаточно для первой части. Надеюсь, что вторая часть будет готова в мае-июне (у меня сейчас мало времени).

      Читать:
      Windows servicing lcu что это

Похожие статьи