Hey, I’m trying to play some water sounds when you’re near water to help my game’s aesthetic. I already implemented this with a water fountain in my game by using an invisible part. But, how would I do it for larger bodies of water like rivers and the ocean? I tried the invisible-part-play-sound method but it doesn’t really work since the parts are WAY bigger, and you have to get closer to the middle of the part to actually hear the sound. Extending the range and stuff isn’t an option because the sound is still going to be coming from the middle. How would I get it to play when you’re just close to it, like on the side? I was thinking of just locally playing the sounds and using Region3s but I wanna know if there’s a better way to do this
EDIT: A more in-depth explanation of what I want
The only reason why I used this simple method was because it’s for a fountain, which is something that you can easily lay 1 part over, and then just Play the sound on the server and utilize roll off modes and play with the range for a good result. Also, a fountain has a fixed middle.
Rivers and oceans don’t have a fixed middle, and i only need the sound to play when you get close to any area of the part, and not to have it just emanate from the middle.
The “distance to point” method you used is really nice because it’s so simple. Thankfully we can also do a “distance to line segment” method that would work great for rivers. Distance to point makes a sphere- shaped region, distance to line segment makes a capsule-shaped region.
We can find that kind of distance with maths, but it’s already been done before so let’s just google how to do it. Here’s a stackoverflow result showing how it can be done with code, and here’s a port to Lua from an earlier reply I posted.
In your case this might also work for the ocean. If players can’t actually travel on the ocean and can only be near the coast, then the coast can be made up of a bunch of line segments just like a river. Let me know if your use case makes this not work and I’ll come up with another way if I can.
EDIT: Part of what made your fountain solution nice is that you can use an invisible part to represent the center of the sphere-shaped region, so you can edit the sphere in a visual and interactive way. The same can be done with line segments! A line segment can be represented by the points at the Front and Back faces of a Part, and you can get the endpoints like so:
function partEndPoints( part )
return
(part.CFrame * CFrame.new(0, 0, -part.Size.Z/2)).p,
(part.CFrame * CFrame.new(0, 0, part.Size.Z/2)).p
end
You could even make the width or height of the part affect the max distance from the line segment where it detects players.
For the water, you said you needed to do the invisible-part-play. So, luckily you still hear the sound. So you can just duplicate and spread it across?
The only reason why I used this method was because it’s for a fountain, which is something that you can easily lay 1 part over, and then just Play the sound on the server and utilize roll off modes and play with the range for a good result. Also, a fountain has a fixed middle.
Rivers and oceans don’t have a fixed middle, and i only need the sound to play when you get close to any area of the part, and not to have it just emanate from the middle.
To find the distance from one point to another, you do
function distanceToPoint( p1, p2 )
return (p2 - p1).Magnitude
end
So that’s what it means to “use magnitude”. If you compare this distance to a fixed number, like 5, you’ll get whether or not one point is inside a sphere of radius 5 within the other, because the definition of a sphere of radius 5 is every point that is 5 or less away from the center.
In other words, a function that checks if a point is inside a sphere:
function isInSphere( sphereCenter, sphereRadius, point )
return distanceToPoint( sphereCenter, point ) <= sphereRadius
end
How I'd do it
local coastAmbiance = --whatever sound object you want
local coastAmbianceRegions = game.Workspace:WaitForChild("CoastAmbianceRegions") --some folder containing Parts that represent regions of space
function isInSphereRegion( point, regionPart )
local center = regionPart.Position
--if the part shape is set to sphere, the smallest size component determines the visual size
local radius = math.min(regionPart.Size.X, regionPart.Size.Y, regionPart.Size.Z)
return (point - center).Magnitude <= radius
end
function isInCapsuleRegion( point, regionPart )
local point1, point2 =
(regionPart.CFrame * CFrame.new(0, 0, regionPart.Size.Z * 0.5)).p,
(regionPart.CFrame * CFrame.new(0, 0, -regionPart.Size.Z * 0.5)).p
--Don't use the Z size, as it's being used to define the line segment
local radius = math.min(regionPart.Size.X, regionPart.Size.Y)
return distanceToLineSegment(point, point1, point2) <= radius
end
function isInRegion( point, region )
if region.RegionType.Value == "Sphere" then
return isInSphereRegion(point, region)
elseif region.RegionType.Value == "Capsule" then
return isInCapsuleRegion(point, region)
else
warn("Unknown RegionType in " .. region:GetFullName())
end
end
function isInAnyRegion( point, regions )
for _, region in pairs(regions) do
if isInRegion(point, region) then
return true
end
end
return false
end
while wait(1) do
local character = player.Character
if character and isInAnyRegion(character.HumanoidRootPart.Positiion, coastAmbianceRegions) then
if not coastAmbiance.Playing then
coastAmbiance:Play()
end
else
if coastAmbiance.Playing then
coastAmbiance:Stop()
end
end
end