So I’m making a shooter game, and I want the sound system to be realistic: I want an ambient sound system, so when a player stands inside of a non-collide part a background noise is made. (I also want it to be able to do multiple at once).
As of now, I have a semi-working state. I have a folder in Workspace called AmbientBoxes which holds all the parts the player stands in, and in that folder i have a subfolder called AmbientSounds. I want my script to play the sound corresponding to the part that the player is standing in (eg. when the player is standing in the part named “Ocean”, the “Ocean” sound is played. However, when I stand in a part, it plays all the audios in the AmbientSounds folder at once, rather than just the “Ocean” sound. Here’s my code:
local rep = game.ReplicatedStorage
local wfc = game.WaitForChild
local ffc = game.FindFirstChild
local pwd = game.GetFullName
local gm = wfc(rep, "GlobalModules")
local myMath = require(wfc(gm, "Math"))
local rr3 = require(wfc(gm, "RotatedRegion3"))
local isPointInPart = rr3.isPointInPart
local newCf = CFrame.new
local isA = game.IsA
local newV3 = Vector3.new
local invCf = CFrame.new().inverse
local sgn = math.sign
local clamp = math.clamp
local runser = game:GetService("RunService")
local hb = runser.Heartbeat
local evWait = game.Changed.Wait
local cam = workspace.CurrentCamera
-- speed of the linear fade-in/out
local sp = 1.2
-- preload all ambient sounds
local ambientBoxesLib = wfc(workspace, "AmbientBoxes")
local ambientSoundsLib = wfc(ambientBoxesLib, "AmbientSounds")
local ambientSounds = {}
local ambientSoundDefVolume = {}
for _, sound in ipairs(ambientSoundsLib:GetChildren()) do
assert(isA(sound, "Sound"))
local ambientName = sound.Name
ambientSounds[ambientName] = sound
ambientSoundDefVolume[ambientName] = sound.Volume
sound.Volume = 0
sound.Looped = true
sound:Play()
-- print("loaded ambient sound", ambientName)
end
-- game:GetService("ContentProvider"):PreloadAsync(ambientSounds)
-- preload all ambient boxes
local ambientBoxes = {} -- just an array of boxes
local ambientVolumes = {} -- ambientName -> volume (curr)
local ambientBoxesTouched = {} -- ambientName -> true / false
for _, v in ipairs(ambientBoxesLib:GetDescendants()) do
if isA(v, "BasePart") then
assert(v.Shape == Enum.PartType.Block, "only rectangular bricks are supported"..tostring(v.Shape))
assert(v.Anchored, string.format("ambientSoundSystem: %s is not Anchored", pwd(v)))
assert(v.CanCollide == false, string.format("ambientSoundSystem: %s is collidable", pwd(v)))
local ambientName = v.Name
ambientBoxes[#ambientBoxes + 1] = v
ambientVolumes[ambientName] = 0
-- print("loaded ambient box", v)
end
end
if #ambientBoxes > 100 then
warn("AmbientSoundSystem: more than 100 ambient boxes, count =", #ambientBoxes)
end
spawn(function()
local lastTick = tick()
while evWait(hb) do
local now = tick()
local dt = now - lastTick
-- O(#ambientBoxes)
ambientBoxesTouched = {}
for _, v in ipairs(ambientBoxes) do
local ambientName = v.Name
if isPointInPart(cam.CFrame.p, v) then
ambientBoxesTouched[ambientName] = true
-- print("in", ambientName)
else
-- print("not in", ambientName)
end
end
for ambientName, volume in pairs(ambientVolumes) do
local volume_ = ambientBoxesTouched[ambientName] and 1 or 0
if volume ~= volume_ then
local dir = sgn(volume_ - volume)
volume = clamp(volume + dir * dt * sp, 0, 1)
ambientVolumes[ambientName] = volume
ambientSounds[ambientName].Volume = volume * ambientSoundDefVolume[ambientName]
-- print(string.format("%s %s", dir == 1 and "entered" or "exited", ambientName))
end
end
lastTick = now
end
end)
print("Ambient Sound system setup")
(the AmbientBoxes are highlighted; basically the entirety of the outside of the ship)
I’ve tried multiple different things, including rewriting the script and adjusting about a hundred different parameters (audio, rolloff, emittersize, etc.) entirely to no avail.
Sorry for the long code snippet, but I can’t figure it out for the life of me.
Give me ideas on how I can fix this, or any mistakes I might’ve made. Also for some reason, when I try testing in studio, it doesn’t work properly so I have to play the experience to actually test it. Thanks for your help