Reproduzir sons customizados em FiveM: NUI audio, volume pela distância, formatos

Reproduzir sons customizados em FiveM com NUI audio (SendNUIMessage e um elemento HTML audio), volume baseado em distância, arquivos OGG, xsound e audio banks nativos.

Você tem um arquivo de som, como uma campainha, uma sirene ou uma notificação, e quer reproduzi-lo de um script. FiveM não tem um native simples para arquivos de áudio customizados, então a resposta usual é NUI: uma página web escondida no seu recurso que reproduz o arquivo quando um client script pede. É assim que recursos do estilo interact-sound funcionam. Abaixo você encontra o código, o volume pela distância, os formatos e as outras opções.

Como funciona

  1. O recurso tem uma página HTML (ui_page) com um pequeno script.
  2. O client script envia uma mensagem para a página com SendNUIMessage.
  3. A página cria um objeto Audio com o arquivo e o reproduz.

A página pode ficar invisível e não precisa de focus do mouse.

O recurso

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'

Os arquivos de som devem estar em files, senão a página não consegue carregá-los.

A página 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 vai de 0.0 a 1.0. Valores fora desse intervalo causam um erro, então o código o restringe.

O client script

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)

Agora outro client script pode chamar exports.my_sounds:PlaySound('doorbell', 0.6), e o server pode enviar TriggerClientEvent('my_sounds:play', source, 'doorbell', 0.6) para um jogador, ou -1 para todos eles.

Dica: para um som que um jogador deve ouvir o tempo todo (uma notificação, um ringtone de telefone), isso é tudo que você precisa. Para um som que pertence a um lugar, use a versão de distância abaixo.

Volume baseado em distância

Para um som em um ponto, como um alarme em um prédio, o server envia as coordenadas e cada cliente decide como o som é:

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)

Isso verifica a distância uma vez, quando o som começa. Para um som longo onde o jogador se move, envie a posição novamente em intervalos, ou mantenha o objeto de áudio na página e atualize seu volume conforme o cliente envia novos valores. Um som que deve seguir um veículo em movimento é onde uma biblioteca pronta ajuda, como na próxima seção.

Mantenha o server no controle de quem dispara o quê. Se você deixar os clientes enviarem um evento play for everyone, qualquer cheater pode spamear sons para todo o server. Veja secure server events.

Formatos de arquivo e tamanho

  • OGG: o melhor padrão, pequeno e boa qualidade.
  • MP3: também funciona bem e é fácil de encontrar.
  • WAV: funciona, mas é grande. Use apenas para efeitos muito curtos.

Todo arquivo em files é baixado por cada jogador, então mantenha-o curto, mono para efeitos, e comprimido. Remova o silêncio no início do arquivo: um atraso que você ouve no jogo frequentemente vem daí. Se o total é grande, o mesmo aviso se aplica como para outros assets: veja oversized assets.

xsound e outras bibliotecas

Em vez de escrever a página você mesmo, você pode usar uma biblioteca de som como xsound. Ela reproduz áudio de um arquivo ou uma URL em uma posição ou em uma entidade, e pode alterar o volume e a posição depois, o que é adequado para música em um bar ou um boombox que segue um jogador. Leia seu README para seus exports exatos, já que diferem entre versões. A ideia é a mesma: uma página NUI escondida reproduz o áudio, e um client script a controla.

Sons nativos e audio banks

Os sons do próprio jogo são outra opção. Eles são reproduzidos com natives como PlaySoundFrontend ou PlaySoundFromCoord, com o nome e set do som, e não precisam de arquivos seus. Adicionar seus próprios sons ao sistema de áudio do jogo também é possível, com arquivos de audio bank e linhas data_file para áudio, mas é um trabalho de especialista com suas próprias ferramentas e é fácil quebrar. Para a maioria dos servidores, NUI audio é mais simples e suficiente.

Problemas comuns

  • Nenhum som. Verifique o nome do arquivo e se o arquivo está em files. Abra o NUI nas ferramentas de desenvolvedor do jogo se você tiver, e leia o console para um 404.
  • Som reproduz apenas uma vez. Crie um novo objeto Audio cada vez, como no código acima, ou resete currentTime em um mantido.
  • Muito alto ou muito baixo. Mantenha volume de 0.0 a 1.0, e defina baixo por padrão.
  • O som é cortado quando o recurso reinicia. A página é recarregada com o recurso. Isso é esperado.
  • Um script que usa interact-sound falha. Recursos que esperam esse nome precisam de um recurso com o mesmo nome e exports. Verifique o que o script quer antes de renomear o seu.

Checklist

Sintoma Solução
Nada reproduz Coloque os arquivos em files e verifique a linha ui_page
Caminho errado Use ./sounds/<name>.ogg relativo à página HTML
Muito alto Restrinja audio.volume entre 0 e 1, e baixe o padrão
Som deve desaparecer com a distância Envie coordenadas e compute o volume no cliente
Download é lento Use arquivos OGG curtos e comprimidos
Fonte móvel (veículo) Use uma biblioteca como xsound, ou atualize o volume conforme o jogador se move

Respostas rápidas

Qual formato de áudio devo usar?

OGG é um bom padrão: arquivos pequenos e bem suportado pelo navegador do jogo. MP3 também funciona. Evite WAV para qualquer coisa longa, pois os arquivos são grandes e cada jogador faz o download deles.

Preciso de SetNuiFocus para reproduzir um som?

Não. Reproduzir áudio do NUI não precisa de focus e nem de interface visível, apenas uma página carregada com ui_page que contém o código de áudio.

Como faço um som ficar mais baixo quando o jogador está longe?

Envie as coordenadas do som para o cliente, meça a distância até o jogador e defina o volume do áudio baseado nisso, por exemplo linearmente de 1 perto a 0 na distância máxima.

Scripts sem esse problema

Arcade MachinesSete jogos de fliperama jogáveis em máquinas de verdade, com rankings e apostas.Ver script →Mic PhoneUm celular dobrável que abre em tablet e chega ao celular de verdade do jogador.Ver script →Crypto MiningCompre um galpão, monte rigs peça por peça e minere moedas num mercado que se mexe.Ver script →

Continue lendo