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?
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
-
Setup a group of parts to represent your ‘zone’
-
Calculate the maximum and minimum boundaries of this zone
-
Create a Region3 value using these bounds
ᅠᅠᅠᅠᅠ
-
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.
-
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.
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.
Open Source example
I’ve created a free-to-use example which you can take here.
Setup
-
Create your zone out of flat parts and parent these to a folder or model. This is a ‘zone’.
-
Call
:GetPlayersInZone(zone)
to retrieve an array of players within that zone.
Methods
ZoneController:GetPlayersInZone(zone, regionHeight)
- Returns an array of players within the exact zone
- regionHeight is 20 unless specified
ZoneController:GetPlayersInRegion(zone, regionHeight)
- Returns an array of players within the zone’s Region3 (the rough zone area)
- regionHeight is 20 unless specified