This is my first DevForum post so feel free to notify me of any formatting errors.
I’m currently implementing new audio in my game. I have Sounds under transparent bricks that I have been placing to emit the audio. To my understanding, this is the most common way of using Sounds. I have noticed that the audio emits from a single origin point in the center of the brick regardless of its size and shape. This works fine for a majority of applications.
However, I encountered a problem when trying to implement a sound for the ocean that surrounds the map. Originally I thought, I’ll just place a thin brick covering the surface of the ocean. and I set the roll-off distance so that you could hear it on land. I have provided a poorly drawn Paint3D diagram for reference. I assumed that audio would emit from every part of the brick, even the farthest reaches of the surface. I instantly realized that it was emitting from the origin of the part meaning it was only playing in a small area of the ocean. This instantly became a problem.
I tried setting the roll-off distance to be massive and encompass the entire ocean but the edge of the sea was quiet and the center was loud, this ruined the effect of the roll-off. I then tried a different method. I placed a grid of Sound emitters covering the ocean and spaced them apart based on their roll-off distance so they did not overlap or have dead zones. The problem returned as I noticed that there were now loud spots in the ocean and I was still encountering dead zones and overlap. I have also provided a diagram of this method.
To make the sound play the same way no matter the position, you can just put it under the Workspace (not in a part). After that, you could get the y position of the player, and change the volume of the sound based on that.
Adding onto what @DevBoardQuestions said, I would suggest you perhaps gather the position of the player in very small intervals, either on runService:BindToRenderStep() or use wait(0.1) in a loop if the former seems overkill. Is the ocean flat throughout the entire game? If how loud the music is will always be determined by how high up you are, gather the user’s Y position in the methods I mentioned, and set the volume based off of that value.
Make sure though the part isn’t in workspace but in SoundService as that is where sounds are meant to be to optimize the game, this also allows for more control over the sound and allows the actual SoundService in scripts and all functions that come with it.
What if it’s a local script? And it tracks the current player’s position? That way when the player walks it will be the same volume. And then lock the Y position to where the ocean is. I mean it’s very similar to @Y35X’ suggestion, the only difference is that in this case it’s the X and Z that moves, and the Y stays locked.
You need to play the sound on the client, (local script) under workspace, or under your head part, only play the sound when you are in the region of the ocean, and manually control volume depending on your Y position vs the ocean’s surface Y
Find the Y value of the ocean. This will obviously be maximum volume.
How much you want it to roll off is completely up to you and depends on how “tall” your game is or how high up the player can go. Once you have this limit set in mind, you simply solve for it.
In this script, I assume that the game goes up to be 50 studs tall. You can change the value maxHeight to be however tall you want it to be. I am using runService for this.
runService:BindToRenderStep("Before camera", 199, function()
--- those values in the parentheses are simply making it so whatever we are doing happens before the camera loads.
local playerPosition = player.Character.HumanoidRootPart.Position
local groundFloor = game.Workspace.OceanPart.Position.Y
local multiplier = playerPosition.Y - groundFloor
local maxHeight = 50 -- change 50 to desired value
game.SoundService.OceanSound.Volume = 1 - (multiplier/maxHeight)
end)
Big thanks for the help, I ended running with this script (modified version of yours)
local oceanSFX = game.SoundService:WaitForChild("OceanSound")
local simulatedArea = workspace:WaitForChild("OceanFloor")
local runService = game:GetService("RunService")
local player = game.Players.LocalPlayer
while true do
wait(0.1)
local playerPosition = player.Character.HumanoidRootPart.Position
local groundPosition = simulatedArea.Position.Y
local multiplier = playerPosition.Y - groundPosition
local maxHeight = 150 -- Adjust
oceanSFX.Volume = (1 - (multiplier/maxHeight)) - 0.2
end