Воспроизведение пользовательских звуков в FiveM: NUI аудио, громкость по расстоянию, форматы

Воспроизведение пользовательских звуков в FiveM с помощью NUI аудио (SendNUIMessage и HTML элемента audio), громкость на основе расстояния, файлы OGG, xsound и встроенные аудиобанки.

У вас есть звуковой файл, например звонок в дверь, сирена или уведомление, и вы хотите воспроизвести его из скрипта. FiveM не имеет простого встроенного инструмента для пользовательских аудиофайлов, поэтому обычный ответ — NUI: скрытая веб-страница в вашем ресурсе, которая воспроизводит файл, когда скрипт клиента просит об этом. Так работают ресурсы в стиле interact-sound. Ниже вы найдете код, громкость по расстоянию, форматы и другие варианты.

Как это работает

  1. Ресурс имеет HTML-страницу (ui_page) с небольшим скриптом.
  2. Скрипт клиента отправляет сообщение на страницу с SendNUIMessage.
  3. Страница создает объект Audio с файлом и воспроизводит его.

Страница может оставаться невидимой и не требует фокуса мыши.

Ресурс

text
resources/[mic]/my_sounds/
  fxmanifest.lua
  client.lua
  html/
    index.html
    sounds/
      doorbell.ogg
      alarm.ogg
lua
-- fxmanifest.lua
fx_version 'cerulean'
game 'gta5'

ui_page 'html/index.html'

files {
    'html/index.html',
    'html/sounds/*.ogg',
}

client_script 'client.lua'

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

HTML-страница

html
<!DOCTYPE html>
<html>
<body>
<script>
  window.addEventListener('message', (event) => {
    const data = event.data
    if (data.action !== 'play') return

    const audio = new Audio('./sounds/' + data.file + '.ogg')
    audio.volume = Math.min(Math.max(data.volume ?? 1.0, 0), 1)
    audio.play().catch((err) => console.log('sound error', err))
  })
</script>
</body>
</html>

audio.volume варьируется от 0.0 до 1.0. Значения вне этого диапазона вызывают ошибку, поэтому код ограничивает его.

Скрипт клиента

lua
local function playSound(file, volume)
    SendNUIMessage({
        action = 'play',
        file = file,
        volume = volume or 1.0,
    })
end

RegisterNetEvent('my_sounds:play', function(file, volume)
    playSound(file, volume)
end)

exports('PlaySound', playSound)

Теперь другой скрипт клиента может вызвать exports.my_sounds:PlaySound('doorbell', 0.6), и сервер может отправить TriggerClientEvent('my_sounds:play', source, 'doorbell', 0.6) одному игроку или -1 всем.

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

Громкость на основе расстояния

Для звука в точке, например сигнализации на здании, сервер отправляет координаты, и каждый клиент решает, насколько громко она звучит:

lua
-- client.lua
RegisterNetEvent('my_sounds:playAt', function(file, coords, maxDistance, baseVolume)
    local pos = GetEntityCoords(PlayerPedId())
    local dist = #(pos - vec3(coords.x, coords.y, coords.z))

    if dist >= maxDistance then return end

    local volume = (1.0 - dist / maxDistance) * (baseVolume or 1.0)
    playSound(file, volume)
end)
lua
-- server.lua: everyone gets it, only players in range hear it
TriggerClientEvent('my_sounds:playAt', -1, 'alarm', vec3(120.0, -1300.0, 29.0), 40.0, 1.0)

Это проверяет расстояние один раз, когда звук начинается. Для длительного звука, где игрок движется, отправьте позицию снова через интервалы или сохраните объект аудио на странице и обновляйте его громкость по мере отправки клиентом новых значений. Звук, который должен следовать за движущимся транспортным средством, — это то место, где готовая библиотека помогает, как в следующем разделе.

Держите сервер под контролем того, кто что инициирует. Если позволить клиентам отправлять событие «воспроизвести для всех», любой читер может спамить звуки всему серверу. Смотрите события сервера и безопасность.

Форматы и размер файлов

  • OGG: лучший выбор по умолчанию, маленький и хорошего качества.
  • MP3: тоже хорошо, и легко найти.
  • WAV: работает, но большой. Используйте только для очень коротких эффектов.

Каждый файл в files скачивается каждым игроком, поэтому делайте его коротким, моно для эффектов и сжатым. Обрежьте тишину в начале файла: задержка, которую вы слышите в игре, часто исходит из этого. Если общий объем велик, применяется то же предупреждение, что и для других активов: смотрите перегруженные активы.

xsound и другие библиотеки

Вместо написания страницы самостоятельно вы можете использовать звуковую библиотеку, такую как xsound. Она воспроизводит аудио из файла или URL в позиции или на сущности и может позже изменять громкость и позицию, что подходит для музыки в баре или портативной колонки, которая следует за игроком. Прочитайте её README для точного синтаксиса экспортов, так как они различаются между версиями. Идея та же: скрытая NUI страница воспроизводит аудио, а скрипт клиента управляет им.

Встроенные звуки и аудиобанки

Встроенные звуки игры — еще один вариант. Они воспроизводятся с помощью встроенных функций, таких как PlaySoundFrontend или PlaySoundFromCoord, с именем и набором звука, и не требуют файлов от вас. Добавление собственных звуков в аудиосистему игры также возможно с помощью файлов аудиобанков и строк data_file для аудио, но это специализированная работа с собственными инструментами и легко сломать. Для большинства серверов NUI аудио проще и достаточно.

Распространенные проблемы

  • Вообще нет звука. Проверьте имя файла и что файл находится в files. Откройте NUI в инструментах разработки игры, если они у вас есть, и прочитайте консоль на предмет 404.
  • Звук воспроизводится только один раз. Создавайте новый объект Audio каждый раз, как в коде выше, или сбросьте currentTime на сохраненный.
  • Слишком громко или слишком тихо. Держите громкость от 0.0 до 1.0 и устанавливайте её низко по умолчанию.
  • Звук прерывается при перезагрузке ресурса. Страница перезагружается с ресурсом. Это ожидается.
  • Скрипт, использующий interact-sound, не работает. Ресурсы, ожидающие это имя, нуждаются в ресурсе с тем же именем и экспортами. Проверьте, что хочет скрипт, прежде чем переименовывать свой.

Контрольный список

Симптом Исправление
Ничего не воспроизводится Поместите файлы в files и проверьте строку ui_page
Неверный путь Используйте ./sounds/<name>.ogg относительно HTML страницы
Слишком громко Ограничьте audio.volume от 0 до 1 и понизьте значение по умолчанию
Звук должен затухать с расстоянием Отправьте координаты и вычислите громкость на клиенте
Скачивание медленное Используйте короткие OGG файлы и сожмите их
Движущийся источник (транспортное средство) Используйте библиотеку, такую как xsound, или обновляйте громкость по мере движения игрока

Короткие ответы

Какой формат аудио я должен использовать?

OGG — хороший выбор по умолчанию: маленькие файлы и хорошо поддерживаются браузером игры. MP3 также работает. Избегайте WAV для чего-либо длительного, так как файлы большие и каждый игрок их скачивает.

Нужен ли мне SetNuiFocus для воспроизведения звука?

Нет. Воспроизведение аудио из NUI не требует фокуса и видимого интерфейса, только загруженную страницу с ui_page, содержащую код аудио.

Как сделать звук тише, когда игрок далеко?

Отправьте координаты звука клиенту, измерьте расстояние до игрока и установите громкость аудио на основе этого, например линейно от 1 близко до 0 на максимальном расстоянии.

Скрипты без этой проблемы

Arcade MachinesСемь аркадных игр в настоящих автоматах, с таблицами рекордов и ставками.Смотреть скрипт →Mic PhoneСкладной телефон, который раскладывается в планшет и работает и на настоящем телефоне игрока.Смотреть скрипт →Crypto MiningКупите склад, соберите фермы по деталям и майните монеты на живом рынке.Смотреть скрипт →

Читайте также