Alternative Activation for Region3 other than a loop?

Is there any way else to index when a player has entered another region of Region3? Because every time the loop calls back in my game, which i have on every 5 seconds, creates a snapping lag thing. I’m also using the Aero Game Framework which i love very much, the script is very much working, but i just wish there wasnt that snap, and instead when the player enters another zone it triggers. Here is my code:

	local BouldaronPoint1 = RegionMarkers.Bouldaron:WaitForChild("RegionMarker1").Position
local BouldaronPoint2 = RegionMarkers.Bouldaron:WaitForChild("RegionMarker2").Position
local Bouldaron = Region3.new(
	Vector3.new(math.min(BouldaronPoint1.X, BouldaronPoint2.X), math.min(BouldaronPoint1.Y, BouldaronPoint2.Y), math.min(BouldaronPoint1.Z, BouldaronPoint2.Z)),
	Vector3.new(math.max(BouldaronPoint1.X, BouldaronPoint2.X), math.max(BouldaronPoint1.Y, BouldaronPoint2.Y), math.max(BouldaronPoint1.Z, BouldaronPoint2.Z))
)

local NamaramorePoint1 = RegionMarkers.Namaramore:WaitForChild("RegionMarker1").Position
local NamaramorePoint2 = RegionMarkers.Namaramore:WaitForChild("RegionMarker2").Position
local Namaramore = Region3.new(
	Vector3.new(math.min(NamaramorePoint1.X, NamaramorePoint2.X), math.min(NamaramorePoint1.Y, NamaramorePoint2.Y), math.min(NamaramorePoint1.Z, NamaramorePoint2.Z)),
	Vector3.new(math.max(NamaramorePoint1.X, NamaramorePoint2.X), math.max(NamaramorePoint1.Y, NamaramorePoint2.Y), math.max(NamaramorePoint1.Z, NamaramorePoint2.Z))
)

local WildernessPoint1 = RegionMarkers.Wilderness:WaitForChild("RegionMarker1").Position
local WildernessPoint2 = RegionMarkers.Wilderness:WaitForChild("RegionMarker2").Position
local Wilderness = Region3.new(
	Vector3.new(math.min(WildernessPoint1.X, WildernessPoint2.X), math.min(WildernessPoint1.Y, WildernessPoint2.Y), math.min(WildernessPoint1.Z, WildernessPoint2.Z)),
	Vector3.new(math.max(WildernessPoint1.X, WildernessPoint2.X), math.max(WildernessPoint1.Y, WildernessPoint2.Y), math.max(WildernessPoint1.Z, WildernessPoint2.Z))
)

local Wilderness2Point1 = RegionMarkers.Wilderness2:WaitForChild("RegionMarker1").Position
local Wilderness2Point2 = RegionMarkers.Wilderness2:WaitForChild("RegionMarker2").Position
local Wilderness2 = Region3.new(
	Vector3.new(math.min(Wilderness2Point1.X, Wilderness2Point2.X), math.min(Wilderness2Point1.Y, Wilderness2Point2.Y), math.min(Wilderness2Point1.Z, Wilderness2Point2.Z)),
	Vector3.new(math.max(Wilderness2Point1.X, Wilderness2Point2.X), math.max(Wilderness2Point1.Y, Wilderness2Point2.Y), math.max(Wilderness2Point1.Z, Wilderness2Point2.Z))
)

local SoundRegions = {
	Bouldaron = Bouldaron,
	Namaramore = Namaramore,
	Wilderness = Wilderness,
	Wilderness2 = Wilderness2
}

local SoundType = {
	Bouldaron = "City",
	Namaramora = "City",
	Wilderness = "Nature",
	Wilderness2 = "Nature"
}


local RegionSound = Instance.new("Sound")
RegionSound.Name = "Region_Sound"
RegionSound.Parent = workspace
RegionSound.Looped = true
RegionSound.Volume = .3

while true do wait(5)
	for Table,Item in pairs(SoundRegions) do
		for partname, part in pairs(workspace:FindPartsInRegion3WithWhiteList(Item, {Player.Character}, 10)) do
		    if part.Parent:FindFirstChild("Humanoid") and part.Parent.Name == Player.Name then
				local ST = SoundType[Table]
				if RegionSound.SoundId ~= "rbxassetid://"..Sounds[ST] then
					RegionSound:Stop()
	
					print(Sounds[Table], "Is the sound of the thing you are in")
			    	RegionSound.SoundId = "rbxassetid://"..Sounds[ST]
					RegionSound:Play()
				end
			end
		end
	end
end
1 Like

If you’re only using this to enable some ambient regional sound, I would recommend running this on the client using RunService Heartbeat.

However, if you want every player to hear the sound. I’d recommend setting up a remote event which fires whenever the client thinks it’s inside the region. On the server you will check their position and then play/stop the sound.

1 Like

Its on the client. Ill look into the heartbeat thing, i’ve never used it.

If it’s on the client I recommend using heartbeat or just removing the five second wait.

So i’m playing with heartbeat, and it seems to just be lagging way way way way more than before. What would happen if i removed the 5 second wait? Wouldnt it run on a fast loop taht would hog my fps?

I’m pretty sure it’s due to the way you’re doing it. I’m currently on mobile and about to go out.

I made a tutorial on this a while ago:

Speaking from personal experience: Regions are always laggy on Roblox. I would note the center positions of regions and do magnitude comparisons constantly, maybe using heartbeat.

(TorsoPosition - RegionPosition).Magnitude will give you the distance between a region’s center and the player. Do a comparison to know if the player is in or not.

Just be aware that this will make a sphere instead of a cube and watch out for 49% of the player being in the region and undetected.

You can check multiple part magnitudes to know how much of the player is inside, it will still be much better performance-wise. It will indeed make a sphere but I don’t think that is an issue.

1 Like

Absolutely, just stating in case someone else stumbles upon this and their use relies on a cube, for example playing sound only in a cuboid room, or where the region is significantly longer than it is wide or tall (for example different floors in a building)

1 Like

A sphere will not cover a rectangular area, i’m trying to limit the amount of outdoor regions i do have, so i think square is better. I’ve been trying to use heartbeat and render stepped, but both create lag. Looping through all the regions in a place like what i’m working with.

I also dont wana use blocks, with a touched event, because first its unreliable, and second i have projectiles that it will effect, even with a hit ignore thing, its still far more blocks than i want. Plus blocks cant cover the radius i want to cover.

Heartbeat shouldn’t have as much of an impact. Have you tried performing a different check on each event? For example, if you have 4 regions, you could do one per Heartbeat, therefore doing each region only once per 4 Hearbeats.

If your number of regions is going to be a lot higher, then you might want to do something else, but provided the number is low:

local regionIndex = 0

game:GetService( 'RunService' ).Heartbeat:Connect( function ()
    regionIndex = regionIndex % #SoundRegions + 1
    -- DO YOUR CHECK ON SoundRegions[ regionIndex ] HERE
end )

This will help spread the load out, as you’ll be taking 1/4 of the time per heartbeat than you currently are.

I’ll try this. However, will it reset by itself, i mean, i don’t have to reset regionIndex at anypoint? and if i do, how would you do it?

This part will take it back to 1 after reaching the number of SoundRegions. You don’t have to do anything other than put your code in there, and instead of a for loop running through all the regions, you just use the one region SoundRegions[ regionIndex ]

% is the modulo operator and essentiall a % n gives you the remainder after n is taken away from a as many times as possible.
5 % 3 = 2.
100 % 30 = 10.
20 % 10 = 0.

Thankyou for your help and patience, i will give it a try :slight_smile:

1 Like

For some odd reason it wont index the regionIndex in the sound regions with SoundRegion[regionIndex]. Im very familiar with tables so i must be doing something dumb. i’m even printing, and its coming out nil.

My mistake - didn’t realise the table was a dictionary. Slightly harder with a dictionary so if I were you I’d change it to something like this:

-- YOUR EXISTING REGIONS SETUP

local SoundRegions = {
	{ Bouldaron, "City" },
	{ Namaramore, "City" },
	{ Wilderness, "Nature" },
	{ Wilderness2, "Nature" },
}

local RegionSound = Instance.new("Sound")
RegionSound.Name = "Region_Sound"
RegionSound.Parent = workspace
RegionSound.Looped = true
RegionSound.Volume = .3

local regionIndex = 0

game:GetService( 'RunService' ).Heartbeat:Connect( function ()
    regionIndex = regionIndex % #SoundRegions + 1

    local region = SoundRegions[ regionIndex ][ 1 ]
    local ST = SoundRegions[ regionIndex ][ 2 ]

		for partname, part in pairs(workspace:FindPartsInRegion3WithWhiteList(region, {Player.Character}, 10)) do
		    if part.Parent:FindFirstChild("Humanoid") and part.Parent.Name == Player.Name then
				if RegionSound.SoundId ~= "rbxassetid://"..Sounds[ST] then
					RegionSound:Stop()
	
					print(ST, "Is the sound of the thing you are in")
			    	RegionSound.SoundId = "rbxassetid://"..Sounds[ST]
					RegionSound:Play()
				end
			end
		end
	end
end )

1 Like

Okay, this is how i’ve been indexing the regions when the game starts:

for _,region in pairs(RegionMarkers:GetChildren()) do
		
		local Point1 = region:WaitForChild("RegionMarker1").Position
		local Point2 = region:WaitForChild("RegionMarker2").Position
		
		local region3 = Region3.new(
			Vector3.new(math.min(Point1.X, Point2.X), math.min(Point1.Y, Point2.Y), math.min(Point1.Z, Point2.Z)),
			Vector3.new(math.max(Point1.X, Point2.X), math.max(Point1.Y, Point2.Y), math.max(Point1.Z, Point2.Z))
		)
		
		SoundRegions[region.Name] = region3
		print(region.Name,SoundRegions[region.Name])
end

So i put regions in the dictionary after the game starts.

I’m just trying to get straight the cleanest way of producing the dictionary so that it can run efficiently

My original problem was with the while true loop there was a weird snapping thing that would happen every time the loop restarted.