Parent : [[INDEX-FIVEM-GAMEPLAY]]
FiveM - Sound System with Distance Attenuation : local, global, distance-based via NUI
Problème
Les sons dans FiveM doivent être spatialisés (entendu uniquement à proximité), et il faut éviter de charger des fichiers audio côté client sans contrôle serveur.
Solution
Système sonore via NUI SendNUIMessage avec 3 modes : local (une personne), global (tous), distance-based (Vdist), déclenché par events serveur.
-- server.lua : forwarding events
RegisterNetEvent('InteractSound_SV:PlayWithinDistance')
AddEventHandler('InteractSound_SV:PlayWithinDistance', function(maxDistance, soundFile, soundVolume)
local src = source
TriggerClientEvent('InteractSound_CL:PlayWithinDistance', -1, src, maxDistance, soundFile, soundVolume)
end)
RegisterNetEvent('InteractSound_SV:PlayOnAll')
AddEventHandler('InteractSound_SV:PlayOnAll', function(soundFile, soundVolume)
TriggerClientEvent('InteractSound_CL:PlayOnOne', -1, soundFile, soundVolume)
end)
-- client.lua : distance check
RegisterNetEvent('InteractSound_CL:PlayWithinDistance')
AddEventHandler('InteractSound_CL:PlayWithinDistance', function(playerNetId, maxDistance, soundFile, soundVolume)
local lCoords = GetEntityCoords(PlayerPedId())
local eCoords = GetEntityCoords(GetPlayerPed(GetPlayerFromServerId(playerNetId)))
local distIs = Vdist(lCoords.x, lCoords.y, lCoords.z, eCoords.x, eCoords.y, eCoords.z)
if distIs <= maxDistance then
SendNUIMessage({
transactionType = 'playSound',
transactionFile = soundFile,
transactionVolume = soundVolume
})
end
end)
-- NUI HTML/JS (html/index.html)
window.addEventListener('message', function(event) {
if (event.data.transactionType === 'playSound') {
var audio = new Audio('sounds/' + event.data.transactionFile + '.ogg');
audio.volume = event.data.transactionVolume || 0.5;
audio.play();
}
});
Pourquoi
Vdistest un calcul rapide de distance euclidienne- NUI HTML5 Audio est plus fiable que les natives GTA pour les fichiers custom
- Le serveur contrôle QUI reçoit l'event (pas de broadcast inutile)
Quand l'utiliser
- Sons d'ambiance (sirenes, klaxons, conversations)
- Sons d'interaction (craft, ouverture de porte, notification proche)
- Musique d'ambiance locale (bars, clubs)
Quand NE PAS l'utiliser
- Musique de fond globale (preférer
TriggerMusicEventnative) - Sons synchronisés précis (tirs d'armes → natives GTA)
Exemples
Correct
-- Son de klaxon avec attenuation par vehicule
RegisterNetEvent('vehicle:honk')
AddEventHandler('vehicle:honk', function(vehNetId)
local src = source
local veh = NetworkGetEntityFromNetworkId(vehNetId)
local coords = GetEntityCoords(veh)
-- Serveur broadcast à ceux dans le rayon
for _, playerId in ipairs(GetPlayers()) do
local ped = GetPlayerPed(playerId)
local pCoords = GetEntityCoords(ped)
if #(coords - pCoords) < 50.0 then
TriggerClientEvent('InteractSound_CL:PlayWithinDistance', playerId, src, 50.0, 'honk', 0.8)
end
end
end)
Incorrect
-- Broadcast global sans distance → lag et immersion cassée
RegisterNetEvent('sound:play')
AddEventHandler('sound:play', function(sound)
TriggerClientEvent('sound:playClient', -1, sound) -- Tout le monde entend tout
end)
Références
- InteractSound/client/main.lua L69-80
- InteractSound/server/main.lua L68-80