How do I accurately check if a player is in a certain area?

How do I accurately check if a player is in a certain area? I need it as accurately as possible, with something happening as long as they are in the area, and stopping as soon as they leave it, and with no rubbish like roblox does it sometimes, when you remove your mouse from a GUI element or you untouch a BasePart, but it does not fire the event for that. What’s the best way I’d go about it?
P.S Characters are R6 if that’s useful

18 Likes

You can use an invisible part and whenever you want to test if the player is in the certain area use part:GetTouchingParts() and check if the player’s HumanoidRootPart is in the dictionary it returns.

Hope that helped!

Edit: Don’t forget to assign a .Touched event that does nothing so a TouchInterest will be in the Part

Edit 2: Code Example

local Part = script.Parent
Part.Touched:Connect(function() end) -- Just for a TouchInterest to occur on a CanCollide false part

function CheckIfPlayerIsInArea(Part,Character)
    local touching = Part:GetTouchingParts()
	for i=1,#touching do
		if touching[i] == Character.HumanoidRootPart then
			return true
		end
	end
	return false
end
67 Likes

I personally create regions for each area represented by a given Position an size, the same way you would see in a normal part. I then check if their torso is inside that given region. If that resolves to true and the region is different than their last region then their current region is updated. If it is false then it resolves to the default region.

Using a system like this you could easily create your own events such as “RegionChanged” or “RegionEntered” to help handle certain things across your game.

3 Likes

Another idea is checking if the character’s position satisfies some mathematical inequalities. For example circle or rectangle (because they are simple to describe in mathematical sense) are the cases where I would consider using my idea if there’s nothing more efficient.

1 Like

Thanks for the reply!
Is :GetTourchindParts() always 100% accurate? If it is, its the simplest way to go about my problem, otherwise I probably should use kinkocat’s or Kacper’s solutions, both of which should be accurate but longer and a bit more trickier.

1 Like

Yes, as long as the HumanoidRootPart is touching the Part, it is accurate.

1 Like

You better use Region3, I know what I’m talking about. I tried a few months ago to make a code that would play music once the player touched an invisible part, but every time I jumped, the music stopped playing. I don’t know if it was a bug from Roblox studio or something else, but as soon as I tried Region3, whether it jumped or left, the code worked properly (I’m sorry it’s a bit long and that this story doesn’t have too much to do with the subject). Anyway, this was a simple example of why Region3 is better for me than a Touched Event. Hope it will help you :wink:
P.S.: I deleted my other answer because I sent it to the wrong person (Sorry).

5 Likes

Well, You used :Touched that relies on the user not doing anything, while getting the touching parts you basically just check if the user is there or not. not if it has moved

5 Likes

Ah, I’m sorry, I hadn’t thought about it.

Using maths:

  • For a rectangular set a region in terms of x, y, z, w, h, l such that:
    - x is the x position,
    - y is the y position,
    - z is the z position,
    - w is the width of the rectangular region,
    - h is the height of the rectangular region,
    - l is the length of the rectangular region.
  • Then compare the value of the players parts parts of the body (you could use recursion on each body part) to see if it fits with all the boxes at all the vertexs of the part. If it does then at least 0.001 studs of the players body is within said region.
  • You will have to use magnitude and radius for a circle alongside pythagoras in order to get pin point locations.

This is long though as maths in the third dimension is time consuming - doing that in my A Level project though and I’m predicted to do extremely well thanks to it as I’m not using a built in function.

1 Like

The thing here is that you aren’t really supposed to use GetTouchingParts for a region check. This is reinventing the wheel for resolving functions to check if a position is within another via mathematical equations, using Region3 or whitelist downcasting to a region identifier. The workflows are the same but Touched involves more work because it is a function tied to the physics pipeline.

Touched is not really an accurate or good way to check for presence in a region.

3 Likes

How would I check whenever a player enters the area and exits it without touch? Would I infinitely loop code that checks if the player is in the area?

1 Like

I think I’ll be using that code. I was just recently thinking about how to check if an NPC is in the area. So simple yet so brilliant. LOVE it. The exact type of code I can handle.

Something like that, yeah. You can check the coordinates of the character in 2D space (no height axis), unless you need regions across multiple floors as well which then you’ll need to do 3D space checking.

You can also alternatively set up region parts below the map and do a whitelisted downcast against those parts every frame (with STEPPED, not RenderStepped) to check what region part a player is at. You can then push changes if the region changes between the found value and the current.

An empty touched event for parts without collisions to make GetTouchingParts work is somewhat of an unsupported hack. Luckily it doesn’t cause undue physics simulation but now you’re taking up memory for a blank function which is also called every physics step when an intersection is found.

3 Likes

Why would I prefer detect player’s 2d space over 3d?

It’s use case dependent. In some cases, you may have regions in your world that are layered. For example, imagine a tower with two floors. Each of those floors you want a different region, yes? Therefore, you would need to work in 3D space, adding the Y coordinate, to determine what floor you’re on and thus determine a player region.

Now suppose you have that same tower but you have two regions: inside the tower and outside. You want the tower to be considered a region, regardless of how high the player is. We can then eliminate the need to check for any vertical axis and we can treat the entire X-Z space of the tower as a region.

The short of it is that when you have regions in different vertical heights, you want to check in 3D space. If you just have regions of a map and there doesn’t need yo be any layered regions (ground region plus some on top), we can just work in 2F space and ignore pointlessly accounting for height.

By the way, if you’re interested in region code because you want to make a sound system, SoundService.AmbientReverb has some great starter code you can reference from. It works in 3D space to define a cave ambient region, so anything above or below the cave is not part of the cave region but anything inside is.

Using the same scenario above: if we wanted to just make a whole section of the map a region regardless of where you were (even inside the cave), ignore height, just check 2D space. There are cases where you can combine them: you check 2D space X-Z for one region and Y to check for layered regions.

1 Like

I need to have some pads the player can kinda step on but if they jump or are just above them then it won’t count as stepping off the pad, and I need stuff happening precisely when the player steps onto the pad and steps off, and my scenario isn’t layered
I have a function that lets you check if a vector3 position is above a part’s position:

local function posAbovePart(pos, part)
	local siz = part.Size
	local opos = CFrame.new(pos):ToObjectSpace(part.CFrame)
	local c1 = false
	local c2 = false
	if math.abs(opos.X) < siz.X/2 and math.abs(opos.Z) < siz.Z/2  and opos.Y < 0 then
		return true
	else
		return false
	end
end

Do I just loop it constantly to check if a player is on or not? Is that a good idea performance-wise?
Is looping code constantly infinitely a good idea in general? (I’ve never been in such a scenario before)

1 Like

Ah, so you want to work with 3D space in this case then. What’s your use case: are you intending to make a sort of effect pad? Yeah, it’d be more understandable if you wanted to stick with a physics-based event then.

In terms of looping, you can cut costs immensely by only using a vector check only if a player is near a pad. That way, each iteration the engine performs an inexpensive distance check between a point and your pad’s position: if the point is near the pad, then it can perform the vector check.

The only real expense I see in your code is the creation of a new CFrame which leads me to confusion as to why you don’t do a raw comparison for a passed CFrame. You shouldn’t need to do object construction at all. That aside, nothing else is really expensive here.

Loops are fine. Just use them sparringly and rely more on events, such as from RunService. lso avoid looping where not necessary or preventing heavier operations from running if lighter ones do not pass.

1 Like

Is there a way I can get events that fire when player enters the pad or exits it?

You’ll either have to create your own events or continue using the originally marked solution, I’m afraid.

2 Likes