How could I make a sound get louder or quiet when a player is closer or further from light sources?

Hello, I am making a horror game that is inspired by the backrooms and I am trying to create a system that “dynamically” changes audio to be louder or quieter depending on if the player is near or far from any light sources. I am wondering if it’s possible to create an effect, and if so, how could I achieve this?

The game consists of A TON of light sources and A TON of dark areas, and I don’t find it pleasing to have light humming play when there are no lights in sight.

If you need any clarification or have questions, please feel free to reply!

3 Likes

You could use distance magnitude

2 Likes

My best recommendation would be to use raycasting
Please let me know if you don’t know how to pull this off

1 Like

I can try but I’m not confident that I can make it successful

1 Like

I don’t believe Raycasting is the best solution here. It would work with enough effort but I think the first reply is a far better and cleaner solution if you want to handle this programmatically.

There is a better solution though! Sounds have a distance property as long as the sound is parented within a BasePart. You can easily preview how the sound will sound like by following these steps:

  1. Insert a Sound object into a BasePart
  2. Set the Looped property to true
  3. Set the Playing property to true
  4. Select your BasePart
  5. Pan your camera around!

Then play around with the properties under the “Emitter” tab in the sound object and tune it to your preference!

If you insist on doing this through code a magnitude check should be sufficient to provide you with an accurate distance

local MainPart = --The primary part, like your characters HumanoidRootPart
local SourcePart = --The source part, like another player or a stationary part

local Distance = (SourcePart.Position - MainPart.Position).Magnitude

print(Distance) --The distance is represented in studs, use this number to fine tune your sound volume.```
1 Like

Would this work in my situation, because my game contains over 1k light souces

1 Like

Yes, putting sounds in 1k light sources would probably be the easiest solution, not sure how optimized it would be to iterate through 1k objects just to control distance though so letting the properties handle that would be ideal. I’ve never worked with thousands of sounds in a game before so I’m not sure how viable it is to do that, so if anyone else knows more about how to handle sounds then it would be nice if you could share your insight here!

1 Like

I was just thinking if the player is near a light, the sound plays. If not, the volume is lowered. Not nothing crazy like reparenting and Instance cloning, etc. Just one sound that changes volume

1 Like

I’m pretty sure what he was saying is that what you are asking for already comes with the light object, just change the properties to what @OKevinO listed above

1 Like

if you are kinda lazy, just loop through all of workspace, and its not worth the fps

local RunService = game:GetService("RunService")

local Character = script.Parent -- starter character scripts                        bnn
local Sound = script:WaitForChild("Sound", math.huge)

local MaxVolume = 2

RunService.RenderStepped:Connect(function()
	local Volume = 0
	local CharacterPos = Character:GetPivot().Position
	
	for i, Object : Instance in pairs(workspace:GetDescendants()) do
		local ObjectVolume = 0
		
		if Object:IsA("Light") and Object.Parent:IsA("BasePart") then
			local Range = Object.Range
			local Brightness = Object.Brightness
			
			local Distance = (Object.Parent.Position - CharacterPos).Magnitude
			
			if Distance <= Range then
				ObjectVolume = MaxVolume + (0 - MaxVolume) * (Distance / Range)
			end
		end
		
		if ObjectVolume > Volume then
			Volume = ObjectVolume
		end
	end
	
	print(Volume)
	Sound.Volume = Volume
end)
1 Like

Looping through 1k objects per frame is pretty much fine, but if you increase the light source or change the code to make more calculations, it gets super performance heavy and might ruin players’ experiences.

A workaround might be using regions to detect lights nearby, then loop through them.

local overlapParams = OverlapsParams.new()
overlapParams.FilterDescendantInstances = {workspace.Lights}
overlapParams.FilterType = Enum.RaycastFilterType.Whitelist

local lights = workspace:GetPartBoundsInRadius(humanoidRootPart.Position, RANGE, overlapParams)

for _, light in ipairs(lights) do
    -- you can now check the nearest light by looping through them now
end
2 Likes

This is already possible with the built-in properties of sounds. Use Sound.RollOffMaxDistance / MinDistance for this, usually, it helps to have the RollOffMode set to Linear.

You can use this in unison with the magnitude method to better manage how many sounds are playing in a given workspace for the client. Setting a maximum distance threshold from any light source stops playing those that are outside the threshold.

2 Likes

Is there a built-in property to make it so it only plays one sound from the nearest light at one time? I think you misinterpret the question.

1 Like

We can just delete the sound or reparent the sound if a new target has been picked for the sound.

1 Like

What is different with this and the magnitude method?

It’s the same logic to choose the nearest light but less performance heavy because it loops through fewer lights since I only made it loop through the lights “near” them.

1 Like

Would I want to run this in a loop such as RunService.Heartbeat?

yes so it updates the nearest light every frame. You might need to modify my code and combine it with other ones too.

1 Like

I’d suggest trying and testing both ways as suggested above.
*just put the sound in every light and set the maxrolloffdistance to whatever you want as the distsnce you want a player to be from the light to hear the sound.
*use the magnitude script mentioned.

Play the game both ways to see which has the best performance. I have a place wuth many sounds in it set up using min & maxrolloff and it works well, but I’ve never tried using thousands of sounds.
Maybe try something with streamingenabled to see if it helps.

1 Like

I’ve tried streamingenabled and it caused random lag on studio. I’m getting 60fps without an fps unlocker and honestly, it’s quite smooth for the number of lights there are.