How to detect when player enter/left a area

I’m trying to a system that will detect when a player has enter or left a area. Here is my code.

local run = game:GetService("RunService")

local pos1 = script.Parent.Position - (script.Parent.Size/ 2)
local pos2 = script.Parent.Position + (script.Parent.Size/ 2)
local region = Region3.new(pos1, pos2)

local playersInRegion = {}

run.Stepped:Connect(function()
	wait()
	local PartsInRegion = workspace:FindPartsInRegion3(region , nil, 1000000)
	for _, Part in ipairs(PartsInRegion) do
		if Part.Parent:FindFirstChild("HumanoidRootPart") ~= nil then
			print("Player is in region")
		else
			print("Player in not in region")
		end
	end
end)

My problem is that since the script loop through ever part that is inside the region it will say that the player is not inside the region for ever part inside the region that is not the player

2 Likes

I wrote a response to a response similar to this, it does essentially the same thing, in that it finds when player enter a region and when they leave it. It uses the spatial query API which should allow for rotated parts, respects geometry afaik, et cetera. It also supersedes the Region3 methods which are actually deprecated.

If you need to check every frame (this will cause more calculations to be run more frequently so I really don’t think it’s advisable), you can substitute the loop for a connection, and remove the task.wait call.

for some reason it keep saying I left and enter the part when standing just standing inside it

Consolee

local players = game:GetService('Players')

local playersInPartLastIteration = {} -- players who were in the part in the last iteration
local partToCheckCollision = script.Parent

while true do
	local parts = workspace:GetPartsInPart(partToCheckCollision)
	local playersInPart = {} -- players who are in the part
	for i,v in ipairs(parts) do -- i is the index, v is the part
		local player = players:GetPlayerFromCharacter(v.Parent)
		if player and not table.find(playersInPartLastIteration, player) then -- we check that they weren't in here on the last iteration to ensure this doesn't fire repeatedly every iteration
			table.insert(playersInPart, player)
			print("Player is in part")
		end
	end
	-- now, we check for the players who've been removed from the part
	for i,v in ipairs(playersInPartLastIteration) do -- i is index, v is player
		if not table.find(playersInPart, v) then -- now, check that they were in the part on the last iteration but not this iteration
			print("Player is not in part")
		end
	end
	task.wait(0.1) -- you don't really need to check every frame, 0.1 seconds should suffice
	-- finally, set the last iteration to be the result from this iteration
	playersInPartLastIteration = playersInPart
end

I see, that was an oversight when I initially wrote the post, I’ll fix it after I post this.

This one should work now, it was because although the player was inside the part, it wasn’t being added to playersInPart

local players = game:GetService('Players')

local playersInPartLastIteration = {} -- players who were in the part in the last iteration
local partToCheckCollision = script.Parent

while true do
	local parts = workspace:GetPartsInPart(partToCheckCollision)
	local possiblePlayers = {} -- players who are in the part
	
	for _, part in parts do
		local player = players:GetPlayerFromCharacter(part.Parent)
		if player and not table.find(possiblePlayers, player) then -- we check that their player hasn't been found in the part already, append to the table of possible players
			table.insert(possiblePlayers, player)
		end
	end
	
	for _, player in possiblePlayers do
		if not table.find(playersInPartLastIteration, player) then
			-- the player wasn't found in the last iteration so this is their first time in the part
			print('Player entered part')
		end
	end
	
	for _, player in playersInPartLastIteration do
		if not table.find(possiblePlayers, player) then
			-- player was found in last iteration but not this iteration so this is their first time leaving the part
			print('Player left part')
		end
	end
	
	task.wait(0.1) -- you don't really need to check every frame, 0.1 seconds should suffice
	-- finally, set the last iteration to be the result from this iteration
	playersInPartLastIteration = possiblePlayers
end

If you want to further expand on speed, you can use the player as the index and something truthy as a value for quick lookup instead of using table.find (although be sure to keep a copy of the normal table without quick lookup as it’s faster to iterate through a normal table than a dict)

6 Likes

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.