I want a sound to play when a player stands inside of a part - Broken script

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 :slight_smile:

Have you tried using GetPartsInPart()?

1 Like

After checking the proximity of the player’s parts, take a print of the table. I don’t think the problem is in the volume setting but in the function that gets the parts close to the player.