Zone+ v1 (deprecated) | Retrieving players within an area/zone

v1 is outdated and unsupported, we highly recommend users checkout the greatly improved v2 instead:

v1 (outdated)

ZonePlus v1

Zone  banner

Zone+ is a lightweight application that utilises regions and raycasting to efficiently determine players within an area.


Theory

View

This kind of question has popped up a lot of times over the years so I thought I’d finally address it:

What’s the best method of retrieving players within an area/zone on the server?


Common solutions

  • "Using touched/untouched events!" - This was actually how I handled zone checking when I first began developing. Not only do these work incorrectly (untouched often fires before touched, untouched sometimes never fires at all when leaving a part, etc) but they can cause lag when complex shapes enter them.

  • "GetTouchingParts!" - The one major flaw with this function is it doesn’t work with uncancollided parts. If the player jumps off the part, they won’t be registered. buildthomas and evaera have created a solution for this if you’re interesting in exploring this path.

  • "Magnitude checks!" - Sorry circle worshippers, but the square lovers are going to have something to say here.

  • "Region3" (by itself) - Polgons hate him. Scientists at Cambridge university have found out… no.

  • "Raycasting" (by itself) - Fire ray below player’s character, check if part below, bam! Polygons and circles are happy bunnies now. Shame the server isn’t. This method is fine for small servers, but fails to scale effectively for servers with increasingly larger amounts of players with recursive checks.


The holy grail

Region3 + Raycasting

Method

  1. Setup a group of parts to represent your zone

  2. Calculate the maximum and minimum boundaries of this zone

  3. Create a Region3 value using these bounds

ᅠᅠᅠᅠᅠimage

  1. Get players in this region using FindPartsInRegion3. This function returns a list of parts, which you can use to check for a player’s character.

  2. For the players returned in the region check, fire a ray below from the HumanoidRootPart (not too far as this causes lag). If one of the zone’s parts is returned, we can safely say the player is within that zone.

    image

Benefits

  • No need to unnecessarily check every player within the server. Simply calculate a ‘rough’ area and determine who’s in the exact zone for players within that region.

  • Region3 and raycasting are ‘light-weight’. You can run these multiple times a second with minimal effect to performance.


Example Uses

Safe Zone (using additionalHeight, a loop and 2000 randomly generated parts)

Safe Zone (using uncancollided parts and zone events)

Coin Spawner

Voting Pads

Ambient Areas (client-sided)

https://thumbs.gfycat.com/TangibleFamiliarBufeo-mobile.mp4


Installing & Using

To learn how to install and use Zone+, visit the about section of the docs: https://1foreverhd.github.io/HDAdmin/projects/zoneplus/about/#example-server-sided


See For Yourself!

You can play around with open source examples here:

Zone+ Playground - Roblox


Best Practices

Zone+ provides an efficient way to determine players within an area, however should be used with consideration and is not always the optimal solution:

  1. On the server, zones should be relatively small areas (ideally no more than 200x200x200), otherwise Region3 checks begin to become expensive. Minimise the volume of your zones where possible.

  2. On the server, Zones should not be used extensively and should not cover a large proportion of a map. Zone+ is optimised for minimal, small zones. If you wish to cover a lot of your map, instead consider setting up zones on the client, or creating your own system which fires a ray from all players instead of performing additional unnecessary Region3 checks.

  3. When using zone events (and calling :initLoop() or :initClientLoop()), or calling your own loop, keep the amount of calls per minute to a minimum. By default when :initLoop() is called (with a default delay of 0.1), 600 checks will be performed per minute. Instead, by specifying a delay of 3 seconds (i.e. :initLoop(3)) only 20 checks will be performed per minute). Obviously the greater the delay, the greater the potential period it takes for a zone to detect a player entering or exiting.

  4. On the client, when using events call initClientLoop() instead of initLoop() for situations where you only intend to check for the local player (e.g. in a local sound system). This method bypasses the zones default region3 checks which are unnecessary for most situations on the client.

  5. On the client, a raycast is fired for every zone. (i.e. ray*zone*(1/delay) per second) due to its object-like nature. While this has a negligible impact on performance, creating your own system which simply fires a ray every delay from the local player’s HRP is more efficient (i.e. ray*(1/delay) per second instead)


Resources

Zone+ is actively maintained by the HD Admin Team; feel free to report bugs, suggest features and make pull requests at our repository.


Credit

Special thanks to:

  • @DanzLua for their TypeScript Port of Zone+
  • @H_mzah for assistance with the source control and automation, and additional ideas
  • @Abbaok_origin for the Coin Spawner suggestion, and additional ideas
  • @TheRings0fSaturn for the enhanced boundaries idea
  • The DreamCraft team for assistance with the theory
387 Likes
How to make a "proper" Safe Zone system?
How check if a player is inside an Part?
Zone Capture System
How to find part is in region?
How do I make a part require 2 people for the TouchInteract function to occur?
Area Scripting Dilemma
How To Make A Attacking NPC?
PSA: Using TouchEvents Properly!
How Can I Make Coins Spawn In Different Places?
Give tool when in area remove when out of area
Safe Zone for a tool
Need help with specific zone fog
Flood Escape-like Elevator
Best methods to check if player close to NPC?
Best way to detect if any object is in a region?
Particles in One Region
How to consistently check if player is touching a part
Exploiter proof safe zone?
TouchPart shop gui opening withou touching
How would I check if a player entered an area?
Sword on touch issues
I need with region3s detection
How to teleport back NPC
Which method would be most reliable for Touched?
Spawning parts in rotated part
Make GUI Appear/Unpaper when you step on/off a brick?
What is a good way to detect if a player has entered/left a Region3?
Capture/Domination mechanic, how can i achieve it?
Help on fixing "Touched/TouchEnded" script
Help with making area/regional sound change effects depending on where you are (Help Needed)
Help with making area/regional sound change effects depending on where you are (Help Needed)
My game isn't working with more than one player
Region3 Causes screen freezing, due to the amount of parts
Much more efficient touch tracking?
My game isn't working with more than one player
How to make a "proper" Safe Zone system?
Location System Help
Difficult time trying to figure out how to show GUI when touching a part and then hiding it when not touching the part
Gravity controller
Looking for somebody to make a safe zone
Alternative for .Touched event
What is the difference between Ray and Region3 and how to use both?
Constantly Detect Touch On Part
How can I make my Gui vanish?
Detect if a player is inside a certain area
Detect if a player is inside a certain area
Why is it so hard to make a VIP door?
More efficient method than .Touched
Best method to detect touch for extremely large parts?
Area Music Player Script! [Open Source]
Script should run when inside the part, but runs both when inside, and when outside?!
Script should run when inside the part, but runs both when inside, and when outside?!
Moving A Player With A Platform?
Touch ends when I jump?
Region3 not accurate?
Issue with .Touched and .TouchEnded
Need help on keeping glitchers out of an area not permitted to them
Need help on keeping glitchers out of an area not permitted to them
How do I make an oxygen system for my game?
How do i make a safe zone area?
Touched event is being detected too many times, how do I make sure only one touch is detected?
How would I detect players in a certain region3 without the use of while loops?
Generating a random valid position inside random geometry
.Touched Leave Function
How do i make it so when i go in a certain area, i get a sword
Is there any way I can keep a part in workspace on the server from replicating to the client?
How do I accurately check if a player is in a certain area?
Best way to do a zone system without parts?
Is there an alternative to magnitude?

Thank you for this extremely useful bit of information! :grinning::smirk: “the holy grail” method is something I never even thought about using for finding players within a zone, I’ll be sure to use this a resource for future projects!

14 Likes

I’ve been looking for a good way to get players in a zone for a long time, thank you for this post! :grinning:

2 Likes

This is actually a smart way to go about it. It even supports arbitrary space, which is a huge plus point when working with regions.

This thread dismisses clunky methods and mini-wars about the best way to do this (especially wrt magnitude), then brings the two best methods to the table and has them cooperate: the basis being the raycast and the Region3 being a gatekeeping supportive arm.

Of course, naturally, not all other methods should be dismissed (actually just the last 3) as they do have utility in some cases. Majority of cases seem to be simple area/room scans though so that should be covered well enough by this.

Thank you for sharing. This thread will go a long way.

7 Likes

so, the best way to keep finding players in zone is using loop?

while wait(1) do
    for _,PlayersInZone in pairs(ZoneController:GetPlayersInZone(Workspace.Zone)) do
        print(PlayerInZone)
    end
end
3 Likes

Can you make a Demo place when they are in safe zone and giving them an ForceField and leaving safe zone removes ForceField.

For situations like the safe zone above, a loop works great, assuming you’re not checking too many times a second (a 0.5 second interval for example will be absolutely fine).

As a side-tip, you might want to check out the article colbert wrote on the While Wait-Do Idiom:

4 Likes

now this is epic. i’m most definitely going to use this in the future with my current project.

2 Likes

Interesting methodology! My own game uses GetTouchingParts to determine region occupation and I must say the fact that I didn’t see this simple yet elegant solution is almost insulting to me. I’ll definitely be upgrading my private system to make use of this method.

1 Like

Great post, this will work very well for general areas but it seems like it’d be rather tedious filling in boxes for more “natural” shapes/zones

Like have fun filling that with boxes :eyes:

(Not to state the obvious)

Another solution for more complex shapes to check if a point is inside a polygon is to simply raycast
from anywhere outside the polygon to your point and count how often it hits a side of the polygon.
(Odd # hits = inside). This shouldn’t be very performance intensive at all and should satisfy most use cases

7 Likes

Very much appreciated for making this, since touched/untouched events are a mess. Thank you for this!

1 Like

The method works the same for any type of shape. I believe you may be getting confused with the second image? Instead of creating lots of small boxes within the shape, we instead calculate a single Region3 determined upon the min and max bounds of the shape. Using this Region3, we then get all the players within the rough area, and fire a single ray below their HRP to confirm whether they are in the precise boundary we want to check for:

i.e. p3 and p4 will be returned

7 Likes

I meant making that shape out of parts is pretty tedious to do unless it’s hollow. But if it’s hollow firing a raycast downward won’t really be all that useful. I guess it wouldn’t be too tedious if you built its hollow shell and used some plugin to fill it in. I’m sure one exists

1 Like

Great system. I tested it out by creating a simple weather system.

25 Likes

Maybe you could add a CheckIfPlayerInZone() function?

1 Like

If the use case for this system isn’t key to gameplay, the ultimate solution would be to perform your downward raycast every frame on each of the clients for their respective characters, and when they hit a part identified as part of a zone, you can then fire a bindableevent and a remoteevent to cause stuff to happen both clientside and serverside. Clients could lie and fire the remoteevent when they aren’t actually in the zone, but for many applications, this isn’t important. For example, a zone that players must stand in if they want to participate in a minigame round, or a zone where stepping in it will apply weather effects (as seen in this thread).

If you want to further expand the utility of this module, you could add this clientside solution as a toggleable alternative, because for some requirements, the clientside method just makes more sense. For example, if someone wanted to open a shop UI upon the player entering a zone, it wouldn’t make sense to detect it on the server and then send a remoteevent signal to that player’s client.

1 Like

Do you have any plans on adding Added/Leaving events? Would be neat to have!

Nice idea! This will work effectively if developed with the correct sanity checks.

Absolutely, the article focuses on retrieving multiple players server-side so I haven’t worried about this. Firing a downward ray every x amount of time and checking this against a dictionary of parts is almost all you’ll need to do for the client.

Having a module work effectively for both client and server is definitely something I’d like to do in the future.

What would you be looking to achieve with this?

1 Like

Personally I’d use this feature for the following:

  • Showing a ‘Entered region_name’ or ‘Left region_name’ UI
  • Updating a live vote count on voting pads upon player enter/leave
  • Initiating Cutscenes/camera movements, etc when a player enters a region

These things are currently a pain to do if you’re a part of circle gang (magnitude checks) or using .Touched.

1 Like

This is amazing, saves so much time on this new game, I’m working on for a road name system .

2 Likes