How can I improve this script that checks whether if player is in a Region3

So what my script is supposed to do is that whenever the player moves inside a region3, one of the GUIs will be enabled and whenever they exit the region, it will be disabled.
The code works, but my question is that it may not be the best solution and if anyone has a more efficient method to do it, can someone please tell me? Thanks.

Note) Point 1 and Point2 are stored in the ServerScriptStorage and just contain the points need to create the region. The “RandomUI” is just a ScreenGui with a frame in it.
indent preformatted text by 4 spaces

    --Define Services
local ServerScriptStorage = game:GetService("ServerScriptService")
--Define Folder
local RegionPoints = ServerScriptStorage:WaitForChild("RegionPoints")
local Point1 = RegionPoints:WaitForChild("Point1")
local Point2 = RegionPoints:WaitForChild("Point2")

--Create Region
local regionPart = Region3.new(Point1.Position, Point2.Position)

--Create Visual Region
local visualRegion = Instance.new("Part")
visualRegion.Anchored = true
visualRegion.CastShadow = false
visualRegion.CanCollide = false
visualRegion.Transparency = 0.5
visualRegion.TopSurface = Enum.SurfaceType.Smooth
visualRegion.BottomSurface = Enum.SurfaceType.Smooth
visualRegion.Material = Enum.Material.SmoothPlastic
visualRegion.Parent = game.Workspace
--Define CFrame and Size
visualRegion.CFrame = regionPart.CFrame
visualRegion.Size = regionPart.Size

local ignoreList = {visualRegion}
local playerTable = {}
--Loop through Region

function diableUI()
	for index, player in pairs(game.Players:GetChildren()) do
		--Check to see if the player is real.
		if player.Character then
			local playerGui = player:FindFirstChild("PlayerGui")
			if playerGui then
				local RandomUI = playerGui:FindFirstChild("RandomUI")
				if RandomUI then
					RandomUI.Enabled = false
				end
			end
		end
	end
end

function enableUI(player)
	local PlayerGui = player:WaitForChild("PlayerGui")
	local RandomUI = PlayerGui:WaitForChild("RandomUI")
	RandomUI.Enabled = true
end

while true do
	--Disable player's UIs
	diableUI()
	
	--Enable it only if player is in the region.
	local partInRegion = game.Workspace:FindPartsInRegion3WithIgnoreList(regionPart, ignoreList, math.huge)
	for index, part in pairs(partInRegion) do
		local Player = game.Players:GetPlayerFromCharacter(part.Parent)
		if Player then
			if not table.find(playerTable, Player.Name) then
				table.insert(playerTable, Player.Name)
			elseif table.find(playerTable, Player.Name) then
				--Enable the UI
				enableUI(Player)
			end
		end
	end
	wait(1)
end
2 Likes

If this a script to change the gui of any player within a region3, then this should probably be moved to a localscript. Let each client track their own position and determine if they are or are not in the region. It takes a lot of processing power to determine if a large set of objects are in a region3, so you shouldn’t put that excessive load on the server.

Another thing you could change would be to use FindPartsInRegion3WithWhiteList. I have a script that keeps track of multiple region3’s, and in that situation I only give it the player’s humanoidrootpart as the whitelist, which means it will only check the rootpart and any object that is a child of it, guaranteeing that if that table is not empty, that the player is in the region3.

If you wanted to let this script be more flexible, you could replace your usage of two set points with a part on the workspace. Make the region3 using the top left and bottom right corner, which are (Part.Position + Part.Size / 2) and (Part.Position - Part.Size / 2)

2 Likes

@itsLevande that’s completely right. Having region managed by the server is pointless, because no serious security measures are needed when it comes to GUIs players see and control. Even if region was installed server side, clients could always change GUIs their own way.

Regions are expensive, performance heavy so to say. The larger, the more demanding they are. FindPartsInRegion3WithWhiteList is a good idea and saves a lot of unnecessary checks. A good alternative is the use of magnitude. It’s about vectors and checking distances in coordinate system. An easy way is to find a part that could represent the center of specific area you’d like to cover, ideally positioned on the floor. Checks are done client-side, as the client calculates the magnitude between two vectors (their own position, namely HumanoidRootPart in our case) and center part’s vector.

local Players = game:GetService("Players")

local CENTER_PART = -- custom object path here
local DETECTION_RADIUS = 35 -- radius around center part (in studs)

local character = Players.LocalPlayer.Character or Players.LocalPlayer.CharacterAdded:Wait()
local hrp = character:WaitForChild("HumanoidRootPart")

local GUI = -- GUI path here

while (true) do
	if ((hrp.Position - CENTER_PART.CFrame.Position).Magnitude < DETECTION_RADIUS) then
		GUI.Visible = true
	else
		GUI.Visible = false
	end
	wait(.6)
end

Since both, region as well as magnitude require us to use loops, we can add a simple if statement that breaks the loop should we want it to.

if (stopLoop) then break end
1 Like