Object Tracker & Area Manager (Get events when an instance enters an Area)

Object Tracker & Area Manager

OT&AM is a module that handles the interaction between my other modules. The main purpose of OT&AM is that it can track objects and gives you onLeave/onEnter events when that object interacts with an area. It’s similar to Zone+ only this module supports not only the player but any object, further more it has many more features and it scales much better.


Automatic proximity sensor door

Gui popup

Why should you use it

Code examples

Basic setup

local module = require(game:GetService("ServerStorage"):WaitForChild("OT&AM")) -- require the module

local a1 = module.addArea("SafeZone", workspace:WaitForChild("Zone")) -- add an Area

a1.onEnter:Connect(function(player) -- add listener , it returns the player obj as param since, autoAddCharacter feature sets the player as ObjectKey

    print(player.Name.."  entered!")


a1.onLeave:Connect(function(player) -- add listener

    print(player.Name.."  left!")


Change settings

local module = require(game:GetService("ServerStorage"):WaitForChild("OT&AM")) -- require the module

module.Settings.Heartbeat = 10 -- set another heartbeat

module.Settings.FrontCenterPosition = true -- turn on this feature

module.setAutoAddCharacter(false) -- disable autoAddCharacter feature


OT&AM works by tracking the position of a giving instance. It uses PiP (Point in Polygon) to detect if an object is inside an Area.

Basically, every Heartbeat (the one u set in settings) it loops over each area and checks if an object is inside of it using PIP. Based on that it generates the events.



Nice pros and cons chart!

On the backend side of things, does this function in the same manner as Zone+ or differently?

1 Like

It works interily different. see the documentation,

Thanks for the feedback!

@VerdommeManDevAcc, you didn’t explain well enough and why didn’t you put that in the OP?


@https_KingPie to simply put it if you look at the Code from init.lua this Module will check everything tracked if it’s within an area every Heartbeat.

The why should you use section is just a list of what it does and doesn’t have, it’s not convincing at all, it’s just a comparison list not a pros vs cons or why A is better than B

Nice resource though, I’ll take a more in depth look later.

Also don’t assume that people know what OT and AV is, don’t use made up abbreviations in general

I added an Theory section, but what do you want in the why section then? Also OT and AV are explained in the documentation. I ll edit the topic to use the full names.

This has been really useful for me. Are there any plans to update the module to increase functionality? It would be nice to be able to have settings that can only track the LocalPlayer or track all players (if the module is being run only on the client), tell if a player is in any zone/area (i.e. list all the areas a player is currently in - although this could be done by hand using Area:getObjects() across all objects and then checking if the player is within any of the tables… although it’d be nice to have that built in), etc.

Still very useful module!

Hey, do you mind sharing benchmarks comparing OT&AM and Zone+? I am curious to see how efficient it is before I start using this other than Zone+.

This page contains the benchmarks and also the link to where the benchmarks are stored on the repo.
I made it really easy to compare the methods just enable a script and disable the other and the it will prints the results. You can also see how i benchmark them


the link on the documentation doesnt work, im fixing that ASAP
1 Like

There is already a method that does that, module.getAreas( objectKey or player in this case),

settings that can only track the LocalPlayer or track all players (if the module is being run only on the client)

Good point, I will add support for this in the next release.

Are there any plans to update the module to increase functionality?

I am planning on adding support for all the PartTypes.

This looks sick! I am definitely using this

1 Like

Is there a way currently to get the name of the region when a player or tracked object is inside the region? (assuming that module.addArea( “string name”, the region basepart) actually gives the region a name)

So it checks all listeners to see if they’re in every area every update tick, even if they’re no where near it? :eyes:

Guess performance impact could be negligible if you don’t have a lot of zones or listeners to iterate through, but depending on how fast the zone check call is and what players use it for - this seemingly small issue could add up quick

1 Like

As soon as it found a listener in an Area, it breaks, but yeah even if they are nowhere near it, How would you check if a point is near an Area while keeping a lower footprint than 4 number comparisons (which currently checks if a listener is inside an Area) ? The amount of “zone check call” is variable depending how high the player sets it. I found trying to optimize it that it made either less reliable or it it was actually slower. I’m open for ideas that would optimize this process.

What I mean is if the zones are static, you can use some sort of spatial structure like an octree to get a more narrow list of potential zone candidates for each player.

Basically separating it into broad and narrow phases.

Broad = Get zone candidates from whatever spatial structure you use(3D array of chunks, octree, etc)

Narrow = Using those candidates, get whether a player is inside each candidate or not

as opposed to just checking every zone regardless of whether or not there’s any chance of the player being in them.

Again, if you aren’t using this for hundreds of objects it probably isn’t a big deal

1 Like

Name is indeed the UID (unique identifier) of the area.

Im not sure what you mean with

Is there a way currently to get the name of the region when a player or tracked object is inside the region?

Since you are the one giving the name to it


local module = require(ServerScriptService:WaitForChild("OT&AM"))

local UID = "test"
module.addArea( UID , workspace:WaitForChild("Part1")).onEnter:Connect(function(player) 
     print(player.Name.." Entered ".. UID)
1 Like

Thanks for the suggestion, I will do some research on this.

i think this module is cool and pain free, but it seems hard to keep it in the eyes of other developers… maybe try giving it a unique/smaller name (dont have too though), good job either way. :+1:

1 Like

I am glad you like this module.

but it seems hard to keep it in the eyes of other developers

Not sure what you mean with this, but I personally use the acronym a lot more since it quite a long name.

Anyway, thanks for the feedback!

1 Like