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

Dang… I saw the coin demo and thought all my problems will be solved :smiley: Unfortunately, no… my problem is, when player gets killed in my game, he’s supposed to drop the item he had, but I need to know weather it’s intersecting with other parts, and if so, find the optimal path to take, to un-stick itself, so it never gets lost in buildings. :smiley: I thought i could use this to find how it’s intersecting, so i can move it accordingly (i guess i could make it physics object…)… Still a really useful tool for future!

@CoolShank8

The zones are removed after voting has completed in the example I provided, so you’ll want to create an additional table of information independent of Zone+ to store any further data you need. Using Region3 over .Touched events, and vice versa, shouldn’t impact your ability to store information - can you expand on this?

Touched and Untouched events are typically fine for ‘activations’, such as collecting a coin, however not so much for ‘entering and leaving’ as these events are often unpredictable (untouched often fires before touched, untouched sometimes never fires at all when leaving a part, etc). That’s the primary use behind using region3 and raycasting: reliable data.

In terms of performance: .Touched and .Untouched events are fired every single time an object moves within the part (i.e. 60 frames per second), which becomes performance heavy with multiple complex shapes. In contrast, Zone+ initLoop defaults to 2 ‘checks’ per second (10 in the voting example for more precision), using raycasting and regions which are well optimised internally by Roblox.


@JustaLatvian

:getRandomPoint() returns the randomly generated CFrame value within the zone, along with the ‘zone part’ directly below it, and the intersection vector between this random point and ‘zone part’, which may help you out.

You could also try Thomas/Evaera’s implementation of GetTouchingParts independently of Zone+ which may help you solve this:

1 Like

My point is using .Touched it fires every single time the part is touched, but region3 doesn’t like are you putting the region3 in a while loop to see if the person is in the region3 all the time?

If you’re using the zones playerAdded and playerRemoving events, and have called Zone:initLoop(), then the zone will repeatedly call :getPlayers() (i.e. perform region and raycast checks) in a loop.

The object compares the previous players within the zone against the new ones, and determines when a player enters and leaves based upon this, which is why it’s necessary to call getPlayers() at frequent intervals - the more intervals, the greater the precision, the greater the cost.

Loops aren’t inherently evil if used appropriately. In this scenario they’re fine as region and raycast checks are well optimised internally, and are only being performed a few times a second.

For the voting pads example, the loop is only necessary for the duration of the ‘voting’ period, therefore can be ended as soon as it’s complete.

2 Likes

Oh, loops can be break yea, I undrstand now thanks!

The typescript port now includes coded examples from the playground, thanks to @DanzLua! You can view that here: @rbxts/zone-plus - npm

1 Like


I’m not sure but I think this is happening when I called :removeZone. The zone I am calling removeZone for definitely does exist.

I’ve just deployed a fix for this, thanks for the report! Originally what was happening: when instances from the zone group were destroyed right before the zone being removed, the ‘a part had changed in the group’ event was fired, added to the update queue, then Zone:update() called 0.1 seconds later, only for the zone properties (like signals) to not exist. To prevent this, I now have the auto-updater check the zone is still active before calling this method.

If I have two different zones with the same name, will that cause any problems?

Yes - the zones are stored in a table using the zone name as the key - having two of the same keys is not possible and so according to the source code you’ll bet met with an error:

	local zone = zones[name]
	if zone then
		warn(("%sFailed to create zone '%s': a zone already exists under that name."):format(errorStart, name))
		return false
	end
2 Likes

Does this module have some sort of priority system?
Example: I set Zone B’s priority to 2, and I set Zone A’s priority to 1.
The player is inside Zone B, but also Zone A. If I use the getPlayersInRegion method on Zone A, it wouldn’t return any players. But if I used it on Zone B it’d return the player. It’s kind of hard to explain but I hope you understand what i’m trying to say.

I am looking at the Documentation in the original post but I can’t seem to understand which way I am supposed to do in order to create multiple separate zones. Should I be using ZoneService:createZone() or Zone.new() multiple times?

@AspectW This isn’t directly supported by Zone+, however you can easily achieve this effect by returning a list of players within both regions (using getPlayersInRegion as you mentioned), then making the necessary weight and player comparisons.


@AbandonedRick Both methods create and return a Zone object (createZone calls Zone.new() internally); you can use either to create multiples zones.

If you’re creating zones which don’t need to be referenced from an outside source (e.g. another script), you can simply use local zone = Zone.new(group) to create the zone, then call zone:destroy() to remove it.

Likewise, if you plan on referencing a zone from an outside source, you can do ZoneService:createZone("ZoneName", group) to create the zone, ZoneService:getZone("ZoneName") to retrieve it, and ZoneService:removeZone("ZoneName") to remove it.

2 Likes

Alright, thanks! That’s highly customisable, wow!

Some background before the question, basically I’m trying to create two different zones, and call :initLoop() on the zones at different times depending on the status of Lighting service’s ClockTime. I’m trying to call :endLoop() before initializing the alternative zone but for some reason it’s not switching loops. However the first zone’s events are connected and looping.

If you could please take the time to see how I’ve set this up and maybe guide me in the right direction, I’d really appreciate it.

Regarding output, the prints within the while loop initially prints 1 once then prints 2 whilst it is not cell time, when it is cell time it then prints 6 once then continues printing 5, however the events for the second zone are not looping.

EDIT: I also tried creating 2 zones in 2 different scripts and controlling it that way, still doesn’t seem to work, :endLoop() stops the events from running and :initLoop() doesn’t start the loop for the opposing zone. Here are the pastebin’s for each zone:

PrisonerBoundaryHandlerZ1 - Pastebin.com - Zone 1
PrisonerBoundaryHandlerZ2 - Pastebin.com - Zone 2

1 Like

Looks like Zone:endLoop() was missing a line of code preventing Zone:initLoop() from being called again afterwards. Thanks for the report, this should be fixed now!

2 Likes

Thank youu, it’s working fine now!

Why do I need to add HDAdmin to my game to use this?

HDAdmin is the name of the directory (folder) where modules from projects (such as Zone+, Topbar+, etc) are stored. You may be referring to the the HD Admin Core, which also uses this directory to store modules, however is independently loaded (not from these standalone projects).

Couldn’t you just use CFrame.PointToObjectSpace?
Example (not taking into acount for Y axis here as I’m using this for 2D areas);

local function withinRotatedRegion2(plrPos, zoneBox)
	local objSpace = zoneBox.CFrame:PointToObjectSpace(plrPos);
	
	local zonePos, zoneSize = zoneBox.Position, zoneBox.Size / 2;

	return objSpace.X > -zoneSize.X and objSpace.X < zoneSize.X and
		   objSpace.Z > -zoneSize.Z and objSpace.Z < zoneSize.Z
end;

I use this, and it works perfectly.
It’s light-weight (you probably could also memoize this), and supports rotation.