ZonePlus v3.2.0 | Construct dynamic zones and effectively determine players and parts within their boundaries

This looks really useful and I would be using this in my future games and projects. Thanks for providing this :slight_smile:

2 Likes

First of all Iā€™d like to say great work and thanks for making this open source! Itā€™s been really awesome to experiment and learn from your scripts. I did also have a question in regards to making a zone disable the core roblox backpack gui. Below is what Iā€™ve drafted up.

local Zone = require(game:GetService("ReplicatedStorage").Zone)
local ToolAreas = workspace.ToolAreas
local player = game:GetService("Players").LocalPlayer
local PlayerGui = player.PlayerGui
local tweenService = game:GetService("TweenService")

for _, container in pairs(ToolAreas:GetChildren()) do
	
	local zone = Zone.new(container)	
	-- This is called when the localPlayer enters the zone
	zone.localPlayerEntered:Connect(function()
		player.PlayerGui.SetCoreGuiEnabled(Enum.CoreGuiType.Backpack,false)
	end)
	
	-- This is called when the localPlayer exits the zone
	zone.localPlayerExited:Connect(function()
		player.PlayerGui.SetCoreGuiEnabled(Enum.CoreGuiType.Backpack,true)
	end)
end

Iā€™m getting 0 Errors and 0 warnings in Script Analysis and am not sure where Iā€™m going wrong. Iā€™d appreciate any advice if possible.

1 Like

Can you implement this necessary feature so that we can create ā€œsmallā€ zones within the ā€œbig motherā€ zone? For example, when a player enters a small zone (within the big mother zone) it exits from the big mother zone and then it enters into the small zone and when the player leaves the small zone then it leaves from the small zone and enters the big mother zone, hopefully you can understand since i didnā€™t find this feature in the api.

Your code looks fine except youā€™re calling SetCoreGuiEnabled incorrectly:

player.PlayerGui.SetCoreGuiEnabled(Enum.CoreGuiType.Backpack,false)

should be:

player.PlayerGui:SetCoreGuiEnabled(Enum.CoreGuiType.Backpack,false)
1 Like

You can achieve this with solid modelling (making sure to set the unions collision fidelity to ā€˜Preciseā€™) and zone:bindToGroup:

BindToGroup

for _, container in pairs(lightingAreas:GetChildren()) do
	
	-- Construct the lighting zones and bind them to the same group to ensure that the localPlayer only enters one zone at a time
	local zone = Zone.new(container)
	zone:bindToGroup("EnterOnlyOneZoneAtATime")
	
	-- This is called when the localPlayer enters the zone
	zone.localPlayerEntered:Connect(function()
		print("Entered:", container.Name)
		tweenService:Create(lighting, TweenInfo.new(0.5), zoneLighting):Play()
	end)
	
	-- This is called when the localPlayer exits the zone
	zone.localPlayerExited:Connect(function()
		print("Exited:", container.Name)
		tweenService:Create(lighting, TweenInfo.new(0.5), defaultLighting):Play()
	end)
end

Solid Modelling

End Result

2 Likes

Ohh thatā€™s actually smart, I didnā€™t think about that, Also itā€™s a blessing that youā€™re still helping people here.

1 Like

I found a major issue with this method which is the following:
image

So when using union, it makes multiple hit-boxes inside and that triggers the module so many times which is inconsistent, I donā€™t know how you would even fix this issue, Thatā€™s what iā€™m concerned of
(
I used this feature to show the hit-box geometry
image
)

(However this bug doesnā€™t occur to Block shapes as it has only one geometry)


another example

Hey thanks for the response! But I actually am not seeing the difference between the lines I have in and what you suggested. It looks exactly the same.

What I have.

player.PlayerGui.SetCoreGuiEnabled(Enum.CoreGuiType.Backpack,false)

What you suggested

player.PlayerGui:SetCoreGuiEnabled(Enum.CoreGuiType.Backpack,false)

I know this is how the whole module works so no need to take any action but do you have any other idea to implement my ā€œmother zoneā€ and ā€œsmall zoneā€

ZonePlus functions with spatial queries instead of hit boxes so something there doesnā€™t sound right. Can you share a place file which reproduces this issue of yours?

I recommend testing with print("Entered") and print("Exited"). If that doesnā€™t work, feel free to share the details here. If the print statements do work correctly, I recommend asking for further help in #help-and-feedback

After more tests it seems that the bug can be reproduced by merging an union/a part with a negative part and setting the collision fidelity to ā€œPreciseā€, now the module will leave and enter multiple times if the player moves/jumps at some point

The module appears to be a bit buggy (works 50% of the time) when teleporting to a region about 20k studs away from the origin with streaming enabled opportunistic enabled. Used to works fine, but something went wrong after streamingenabled was modified and oppotunistic was enabled.

Can you send a repo place file of this as I canā€™t reproduce this myself

I canā€™t seem to reproduce this, even when moving the test place over 100,000 studs from the origin and setting the following properties for Streaming enabled:

image

image

Are you ensuring the parts have streamed in before constructing the zones? e.g:

lightingAreas:WaitForChild("Green", math.huge)
lightingAreas:WaitForChild("Pink", math.huge)

Iā€™ve updated the playground if youā€™d like to play around with this:
https://www.roblox.com/games/6166477769/ZonePlus-Playground

@ForeverHD
Found a weird bug with having .playerEntered on the client. Iā€™ve provided a video and the code used.

Basically, the zone doesnā€™t detect a player ( if that 1 player has died ), both players have to die in order for it to be accurately detected once again.

Zone.playerEntered:Connect(function(Player)
     print(Player)
end)

edit : the bug can not be replicated inside of roblox studio, only happens in game.

1 Like

Thanks for your report! Iā€™ve done some digging and it appears there were some cases with streaming which ZonePlus wasnā€™t accounting for. Updating the function on line 87 of the Tracker module to the following should fix this:

image

local function playerAdded(player)
	local function charAdded(character)
		local function trackChar()
			local hrp = character:WaitForChild("HumanoidRootPart", 0.1)
			local humanoid = character:WaitForChild("Humanoid", 0.1)
			local head = character:WaitForChild("Head", 0.1)
			if hrp == nil or humanoid == nil or head == nil then
				return
			end
			updatePlayerCharacters()
			self:update()
			for _, valueInstance in pairs(humanoid:GetChildren()) do
				if valueInstance:IsA("NumberValue") then
					valueInstance.Changed:Connect(function()
						self:update()
					end)
				end
			end
		end
		local hrp = character:FindFirstChild("HumanoidRootPart")
		if hrp then
			task.delay(0.1, trackChar)
		else
			character.ChildAdded:Connect(function(child)
				if child.Name == "HumanoidRootPart" and child:IsA("BasePart") then
					task.delay(0.1, trackChar)
				end
			end)
		end
	end
	if player.Character then
		charAdded(player.Character)
	end
	player.CharacterAdded:Connect(function(char)
		charAdded(char)
	end)
	player.CharacterRemoving:Connect(function(removingCharacter)
		self.exitDetections[removingCharacter] = nil
	end)
end

Iā€™ll deploy this change officially at a later date alongside a group of other updates.

4 Likes

My experiences were teleporting to the area instead of moving to it though, but let me try to send you something

Thanks, this solution works perfectly!