Problem with Region3, trying to detect when the Player is no longer in the region

I have two Parts that serve as two different points for a region to be created: Shop_PointA and Shop_PointB. When the player steps inside of the region, the ScreenGui is enabled. I’m trying to detect when the player steps out of the region so I can disable the ScreenGui.

Here’s my entire code:

local Players = game:GetService("Players")

local shop_PointA = workspace.Shop_PointA.Position
local shop_PointB = workspace.Shop_PointB.Position
local touchedRegion = false

local shopRegion =
		math.min(shop_PointA.X, shop_PointB.X),
		math.min(shop_PointA.Y, shop_PointB.Y),
		math.min(shop_PointA.Z, shop_PointB.Z)
		math.max(shop_PointA.X, shop_PointB.X),
		math.max(shop_PointA.Y, shop_PointB.Y),
		math.max(shop_PointA.Z, shop_PointB.Z)

local ignoreList = {workspace.Shop_PointA,workspace.Shop_PointB}

while true do
	local partsInShopRegion = workspace:FindPartsInRegion3WithIgnoreList(shopRegion,ignoreList,math.huge)
	local isEmpty = workspace:IsRegion3EmptyWithIgnoreList(shopRegion, ignoreList)

	for _,v in pairs(partsInShopRegion) do
		if isEmpty == true then -- This usually gets ignored, not sure what's happening
			Players[v.Parent.Name].PlayerGui.UpdatesBrochure_UI.Enabled = false
			if v.Parent:FindFirstChild("Humanoid")~= nil then
				Players[v.Parent.Name].PlayerGui.UpdatesBrochure_UI.Enabled = true

I’ve also experienced some lag while testing this (most likely to do with the loop). What are some methods I can do to fend off those performance issues?

I’m still quite new to Region3, so first time I’ve attempted on this full-on. Maybe some imporvements?

So what i recommend you do to make this in the most efficient way is something like this:
(also sorry about the my formatting, i always make my code look the same lol)

local function toggleGUIWhenInRegion()
    for _, plr in pairs(game:GetService("Players"):GetPlayers()) do
        plr.PlayerGui.UpdatesBrochure_UI.Enabled = false -- disable it be default

    local partsInRegion = workspace:FindPartsInRegion3WithIgnoreList(shopRegion, ignoreList, math.huge)
    local plrDebounce = {} -- saves performance by only turning on the gui once, even if more than one part of their character is in the region

	for _, v in pairs(partsInRegion) do
        local model = v:FindFirstAncestorOfClass("Model")
        local char = model and model:FindFirstChildOfClass("Humanoid")
        local plr = char and game:GetService("Players"):GetPlayerFromCharacter(char)
        if plr and not plrDebounce[plr.UserId] then
            plrDebounce[plr.UserId] = true
            plr.PlayerGui.UpdatesBrochure_UI.Enabled = true

while wait(0.25) do

As this helps me with my performance issues, I’m unsure how it helps me with my core problem.

it should make all the players that are not in the region have their GUIs turned off and the ones that are should have their GUIs turned on

I’ve attempted to make use of the code you provided above. However, it leads me into a strange error.

It is telling me that the ScreenGui is nonexistent in the PlayerGui even though it is existent while I’m testing In-Studio.

Make sure they are named exactly the same thing, i could have messed it up by accident up there

local partsInRegion = game.Workspace:FindPartsInRegion3(region3Test, nil, math.huge) -- get the possible players in the region --

local currentPlayers = {} -- a table for current players --
local oldPlayers = {} -- a table for older players --

while true do
     oldPlayers = currentPlayers -- set the oldPlayers table to the LAST loop's
     currentPlayers = {} -- clear the table before we work on it.

     for _, part in pairs(partsInRegion3) do -- loop through the current parts in the region3
          local player = game.Players:GetPlayerFromCharacter(part.Parent) -- get the player (or nil if it isn't a character)

          if player then -- check if the player is nil --
               currentPlayers[player.UserId] = player -- set the currentPlayers[userId] slot to the player object
               -- enter code to do what you want on enter --

     for _, player in pairs(oldPlayers) do -- loop through old players --
          if currentPlayers[player.UserId] == nil then -- if this is true, they do not need to be prompted anymore
               -- enter code to do what you want on exit --
     wait(0.5) -- pretty demanding so don't make it update too much

Hope this helped! :slight_smile:

1 Like

I’ve tried it again and unfortunately it still doesn’t work.

This error is strange because I already have a ScreenGui created for the game beforehand and no script is tampering with in. I have also copied the name of my ScreenGui exactly so and pasted it into my script, yet it still errors…?

I’ve explored other options such as using :WaitForChild() but ultimately it breaks the script and gives me no error output at all.


I’ve tried your solution but unfortunately it did not work towards my task. Though, I am curious, do you think that Magnitude would be better suited for this task?

I’ve been doing lots of research on Region3 through devforum posts and videos and honestly it just seems like I can never get it right.

I had the same problem. Try using that two-table method, and MAKE SURE TO SET THE PREVIOUS TABLE, AS WELL AS CLEAR IT. I had MAJOR issues with that when I was trying to learn Region3. Obviously, I can’t control what you do, but I’d recommend you just keep trying to make Region3s work.

local RegionPart = script.Parent
local Region = - (0.5 * RegionPart.Size), RegionPart.Position + (0.5 * RegionPart.Size))

local Watching = {}
while true do
	Parts = workspace:FindPartsInRegion3WithIgnoreList(Region, {RegionPart}, math.huge)
	for i,v in pairs(Parts) do
		if v.Name ~= "HumanoidRootPart" then continue end
		local Player = game.Players:GetPlayerFromCharacter(v.Parent)
		if Player == nil then continue end
		local Character = v.Parent
		local Humanoid = Character["Humanoid"]
		if Humanoid ~= nil then
			Humanoid.MaxHealth = math.huge
			Humanoid.Health = Humanoid.MaxHealth
		if not table.find(Watching, v) then
			Thread = coroutine.wrap(function()
				table.insert(Watching, v)
				while true do
					local IsIn = workspace:FindPartsInRegion3WithWhiteList(Region, {v}, math.huge)
					if #IsIn == 0 then
						Humanoid.MaxHealth = 100
						Humanoid.Health = 100
						for x,c in pairs(Watching) do
							if c == v then
								table.remove(Watching, x)

Modify my safezone script to give a gui instead of health?

Hey guys, I finally figured it out!

I even managed to get some nice tweening in!

local regionArea = workspace.TestRegion
local positionA = regionArea.Position - (regionArea.Size / 2)
local positionB = regionArea.Position + (regionArea.Size / 2)
local region =,positionB)

local playerDebounce = {}
local player = game.Players.LocalPlayer

while true do wait()
	local partsInRegion = workspace:FindPartsInRegion3(region, nil, math.huge)
	local isInRegion = false
	for i, v in pairs(partsInRegion) do
		if game.Players:GetPlayerFromCharacter(v.Parent) == game.Players.LocalPlayer then
			isInRegion = true

	if isInRegion == true then
		if not playerDebounce[player.UserId] then
			script.Parent.Enabled = true
			script.Parent.Frame.Position =,0,0,0)
			playerDebounce[player.UserId] = player
		script.Parent.Frame.Position =,0,0,0)
		script.Parent.Enabled = false
		playerDebounce = {}

This code works perfectly – but my only concern is: can tables with lots of variables cause performance disruptions? Because if the player leaves while the Gui is on the screen, they’re still in the table… unless them leaving makes their own variable become nil? At any rate, let me know!