How would I detect players in a certain region3 without the use of while loops?

I am reworking a racing system I made a while ago, and it used while loops to detect players in a start point and end point. Now I know that using while loops to do that would cause a lot of lag, so I need a good replacement for it. It needs to be a server script so I cannot use RenderStepped. Any suggestions are appreciated.

3 Likes

The hub explains this stuff well: WorldRoot | Documentation - Roblox Creator Hub

2 Likes

You could use RunService.Stepped or RunService.Heartbeat to get a similar implementation to when using RenderStepped.

But it doesn’t actually matter if you use a while loop or listen to an event that fires e.g. 30 times per second. You’ll still be doing calculations 30 times per second.

Have you actually tested it to see if it’s laggy? If it’s not a problem, don’t worry about it.

If you want us to help optimize your code, post it and tell us about your use case so we can take a look.

2 Likes

A module has been released called Zone+ which allows you to detect players inside a region3 area. Yeah, it uses a while loop, but that’s the only way to actually detect players. No, doing a while loop doesn’t lag the game unless you use a heavy task Doing a while loop lags depending on several factors, one of them being the time of the loop and how heavy the loop script is.

3 Likes

I haven’t implemented that part yet as I wanted to see if there is another way of doing it than while loops, but I wanted to fire a bindable to a main script, which looks like this:

local rs = game.ReplicatedStorage

local remotes = rs:WaitForChild("remotes")
local bindables = rs:WaitForChild("bindables")

local races = workspace:WaitForChild("races")

local racesList = {
	
	race1 = {
		
		participants = {},
		finishedPlayers = {},
		available = true,
		started = false,
		preparing = false,
		
	},
	
}

local function getIndex(tab,val)
	
	for i,v in pairs(tab) do
		
		if v == val then
			
			return true,i
			
		end
		
	end
	
	return false
	
end

remotes.addRemove.OnServerInvoke = function(player,raceName,condition)
	
	if #racesList[raceName]["participants"] >= 1 and not racesList[raceName]["preparing"] then
		
		racesList[raceName]["preparing"] = true
		
		bindables.start:Fire(raceName)
		
	end
		
	if condition and not racesList[raceName]["started"] then
		
		table.insert(racesList[raceName]["participants"],racesList[raceName]["participants"]+1,player.Name)
		
	elseif not condition and racesList[raceName]["started"] then
		
		local found,index = getIndex(racesList[raceName]["participants"],player.Name)
		
		if not found then return racesList end
		
		table.remove(racesList[raceName]["participants"],index)
		
	end
	
	return racesList
	
end

bindables.start.Event:Connect(function(raceName)
	
	local count = 10
	
	while wait(1) do
		
		for i,v in pairs(racesList[raceName]["participants"]) do
			
			local player = game.Players[v]
			
			remotes.countDown:FireClient(player,count)
			
		end
		
		count -= 1
		
		if count == 0 then break end
		
	end
	
	races[raceName].checkPoints["1"].Transparency = 0.5
	races[raceName].startLocation.Transparency = 1
	
	racesList[raceName]["started"] = true
	racesList[raceName]["preparing"] = false
	
		
end)

bindables.checkPointFinished.Event:Connect(function(player,raceName)
	
	remotes.showFinishLocation:FireClient(player,raceName,racesList)
	
end)

bindables.finished.Event:Connect(function(player,raceName)
	
	if races[raceName].endLocation.Transparency ~= 0.5 then return end
	
	table.insert(racesList[raceName]["finishedPlayers"],racesList[raceName]["finishedPlayers"] + 1,player.Name)
	
	if #racesList[raceName]["finishedPlayers"] == #racesList[raceName]["participants"] then
		
		for i,finished in pairs(racesList[raceName]["finishedPlayers"]) do
			
			if i == 1 then
				
				game.Players[finished].cash.Value += 200
				
			elseif i == 2 then
				
				game.Players[finished].cash.Value += 150
				
			elseif i == 3 then
				
				game.Players[finished].cash.Value += 100
				
			else
				
				game.Players[finished].cash.Value += 50
				
			end
			
		end
		
		racesList[raceName]["available"] = true
		
	end
	
end)
1 Like

I’m not seeing anything related to Region3 or seeing which players are in a region in the code you posted?

A couple other things:

  • getIndex could be replaced by the built-in table.find.
  • Adding newlines to your code after almost every line is not great. Having newlines to group things that “belong together” is good style, but you’re overdoing it IMO.
1 Like
  1. How would I use table.find to get the index of the value in the table?
  2. I include those newlines in my indentation etiquette, so in all my scripts are like that and they never bothered me :man_shrugging:

That’s what table.find(t, v) does. It returns the index at which v appears in t, or nil if it does not appear.

1 Like

Interesting, I thought it was used solely for if statements, thanks for the info