Zones/Areas for different music

I’m making a new game right now where I need different music to be played in different zones, I tried looking for an solution, but I only found solutions where only 1 part was used to play music in zones, but I need my system to be over several parts as the zones are not like squares but are more round (Like i nthe picture below), any Idea how I could script this?

image

Edit:
image
Ambience should only be played if the player left the zone, and the ambience shouldnt reset when ever the palyer touches another part in the group

2 Likes

Try using a module or smth like that, bc i don’t know how to do that, maybe region2 may be the solution? (even if i don’t know what that is lol, but it has region on the name) and then i discovered that region2 is outdated and it’s not region2 it’s region3

1 Like

I have seen some modules on youtube, try searching for “zone module roblox studio” or something like that

2 Likes
local zones = workspace:WaitForChild("Zones")

local hits = {}

for i,v in ipairs(zones:GetChildren()) do
    v.Touched:Connect(function(hit)
        local character = hit:FindFirstAncestorOfClass("Model")

        if character then
           local player = game.Players:GetPlayerFromCharacter(character)

           if player and not table.find(hits, player) then
               table.insert(hits, player)
               print("entered")
           end
        end
    end)

    v.TouchEnded:Connect(function(hit)
        local character = hit:FindFirstAncestorOfClass("Model")

        if character then
           local player = game.Players:GetPlayerFromCharacter(character)

           if player and table.find(hits, player) then
               table.remove(hits, table.find(hits, player))
               print("left")
           end
        end
    end)
end

or

local RunService = game:GetService("RunService")

local zones = workspace:WaitForChild("Zones")

local overlapParams = OverlapParams.new()
overlapParams.FilterDescendantsInstances = {zones}
overlapParams.FilterType = Enum.RaycastFilterType.Exclude

for i,v in ipairs(zones:GetChildren()) do
    RunService.Heartbeat:Connect(function()
        local parts = workspace:GetPartsInPart(v, overlapParams)

        for _, hit in ipairs(parts) do
            local character = hit:FindFirstAncestorOfClass("Model")

            if character then
               local player = game.Players:GetPlayerFromCharacter(character)

               if player and not table.find(hits, player) then
                   table.insert(hits, player)
                   print("entered")
               end
           end
        end
    end)
end
1 Like

oh this is simple
i used Zone - ZonePlus

and then made zones
did a for loop and got a playerEntered event that zoneplus has
then a dictionary to have all the sound ids

play the if a player entered a region

simple optimized like 80 lines max

1 Like

It didn’t really seem to work, but thanks for writing all the code!

Will it work with making multiple parts representing one zone?, like shown in the picture at the top

1 Like

of course, it will work for multiple zones perfectly fine! wait what did you said?

1 Like

I don’t know how module above works, but…

I personally would apply priority for each part, with table.sort you can sort them on priority, ones scanned first will immediately break the iteration on the zone parts and return such parts.

For each kind of part you would need different math. For Cubes I would use X, Y and Z in zone object space, for spheres I’d use the Magnitude and compare it to the sphere radius.

Using .touched like I’ve seen above can be done too, but I wouldn’t do it personally.

You can also make it so if there is no zone detected, it will go to a fallback option OR not change zone.

I’ve been using sound zones for a while now and it is not hard to set up.

If you have lots of zones, I would recommend not scanning each heartbeat, but rather each few heartbeats, 2, 3 or 4, that is more optimised and barely noticable.

Another way to optimise this is by turning all zones into a table with dictionaries in them first, rather than having to read the properties off the parts themselves.

Yet another way to optimise is by making this run using actors, but that requires slightly more insight into how those work, but I am a great fan of “over”-optimising my games.

1 Like

yeah it needs to be in a model or a folder to work thats how zone works read the documentation

1 Like

You can simply add different Parts to different places of your map, make them all invisible and ‘Uncollidable’ and then check if one of the Parts is touched by the player through a Script. (Also make sure that the property CanTouch is enabled)

And make sure that every part covers its place COMPLETELY

If you want to play Music1 when the player touches Part1, you can say

Part1.Touched:Connect(function()
    Music1:Play()
end)

And if you want to stop the music from playing when the players leaves the place, you can say

Part1.TouchEnded:Connect(function()
    Music1:Stop()
end)

But, If you want to play Music2 when the player touches Part2, you can say

Part2.Touched:Connect(function()
    Music2:Play()
end)

And if you want to stop the music from playing when the player leaves the place, you can say

Part2.TouchEnded:Connect(function()
    Music2:Stop()
end)

And so on

Edit: I didn’t realize that this was already solved :+1: :skull:

1 Like

Yeah… But this type isn’t that efficient, and it is not that organized too… Anyways, i think you just need some kind of tags or something like that, idk, but at least, it is something

1 Like

Yea it’s not very efficient, and can cause bugs, but this is the only way I know to play different sounds in different parts of the map … I’m not that professional either.

Yeaa… me neither, i’m not a professional too, so i get what you’re saying

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.