How can I detect if a player is in a part and when they leave?

Hello,
I’m trying to work with Region3 and let me say, I am very confused. Here’s code I have tried to detect if a player is in a 10,7,10 part. I’m extremely lost and I don’t know how to properly do this and accomplish what I’m trying. If you know something that can help, please feel free to help. If not, have a great rest of your day/night!

for i,v in pairs(game.Workspace.Interections:GetChildren()) do
	if v.Name == "Interaction" then
		
		function CreateREgion(Part)
		    local Size = Part.Size
		    return Region3.new(Part.Position-(Size/2),Part.Position+(Size/2))
		end
		
		CreateRgion(v)
		
		local HumaniodRootPart = Region3FromPart()
		function OnLeave(region3, HumaniodRootPart)		
			local Player =  game.Workspace:FindPartsInRegion3WithWhiteList(region3,  {HumaniodRootPart}) -- you might want to connect/integrate your enter region3 function
				if Player  then
					while Player ~= nil do
					wait(.5)
				    Player = game.Workspace:FindPartsInRegion3WithWhiteList(region3,  {HumaniodRootPart})
				end
				print("player isn't in region anymore?")
				---Player Is no longer in the region3
			end		
		end
		
		OnLeave(Region3FromPart(), HumaniodRootPart)
	end
end
2 Likes

to do this you could do something like this.

local RunService = game:GetService("RunService")

local part = (path to your part here)
local touchingTable = {}


RunService.Stepped:Connect(function()
    touchingTable = part:GetTouchingParts()
    wait()
end)

game.Players.PlayerRemoving:Connect(function(player)
    print(player.Name.." left the game")
    for i,v in pairs(touchingTable) do
        if i == player.Name then
            print(player.Name.." left whilst touching part")
        end
    end
end)

untested so please say if it worked out for you
this script (should) print “[player] left whilst touching part”. change local part at the top to the part you want to test this for
(also first post :slight_smile:)

The script didn’t print “[player] left whilst touching part”, although no errors in output.

i think i know the issue. bare with me i’ll post a working and tested script later

No problem, take your time! I’m in no hurry.

local players = game:GetService("Players")
local interactions = game.Workspace:WaitForChild("Interactions")

local function checkIfPlayerIsInPart(hPartPosition, part)
	local relPos = part.CFrame:PointToObjectSpace(hPartPosition)
	if math.abs(relPos.X) < part.Size.X * 0.5 and math.abs(relPos.Y) < part.Size.Y * 0.5 and math.abs(relPos.Z) < part.Size.Z * 0.5 then
		return true
	end
	return false
end -- Function that returns true if player is within part

players.PlayerRemoving:Connect(function(player)
	local humanoidRootPartPos = player.Character:WaitForChild("HumanoidRootPart").Position
	local inside = false
	for _, part in ipairs(interactions:GetChildren()) do
		if checkIfPlayerIsInPart(humanoidRootPartPos, part) then
			inside = true
			print("Was in region")
			break
		end
	end
	if inside == false then
		print("Wasn't inside region")
	end
end)

I made a function that detects whether your HumanoidRootPart position is within the volume of a part. It returns true if it’s inside and false if it’s not. On player leave, it loops through the group of parts and checks to see if it’s within each part, and if it is, it breaks the function.

You might want to try this out and see if any errors occur!

1 Like

This function can check if a Vector3 position is inside a block:

A possible implementation:

-- Script inside the part
local blockEvent = Instance.new("BindableEvent")
blockEvent.Name = "Event"
blockEvent.Parent = script.Parent

local players = game:GetService("Players")

local function isInsideBrick(position, brick)
	local v3 = brick.CFrame:PointToObjectSpace(position)
	return (math.abs(v3.X) <= brick.Size.X / 2)
		and (math.abs(v3.Y) <= brick.Size.Y / 2)
		and (math.abs(v3.Z) <= brick.Size.Z / 2)
end

local insideBlock = {}

local function check()
	for _, player in ipairs(players:GetPlayers()) do
		if (player.Character and player.Character:FindFirstChild("HumanoidRootPart")) then
			if (isInsideBrick(player.Character.HumanoidRootPart.Position)) then
				if (not insideBlock[player]) then
					insideBlock[player] = true
					event:Fire(player, true)
				end
			else
				if (insideBlock[player]) then
					insideBlock[player] = false
					event:Fire(player, false)
				end
			end
		end
	end
end

game:GetService("RunService").Heartbeat:Connect(check)
-- A different script
local event = workspace["Part"]:WaitForChild("Event")

event.Event:Connect(function(player, entered)
	if (entered) then
		print(player.Name, "entered the box!")
	else
		print(player.Name, "left the box!")
	end
end)

Of course if you want to do all this inside one script you can just leave out the stuff with the bindable event.

2 Likes

I did this and made a few edits because I have a “Range” part inside a few interactions parts and when I am in that part, it print Wasn't inside region

What does range do?

I test this code in studio and it worked for me, so I’m wondering if the edits you made created any errors, or if the script itself created and errors in the output? But if you’d like, I’d love to see your code on handling the “Range” property! :smiley:

Okay, Here is my code and a screenshots of the children in “Interactions”.

-- Code
local function checkIfPlayerIsInPart(hPartPosition, part)
	local relPos = part.CFrame:PointToObjectSpace(hPartPosition)
	if math.abs(relPos.X) < part.Size.X * 0.5 and math.abs(relPos.Y) < part.Size.Y * 0.5 and math.abs(relPos.Z) < part.Size.Z * 0.5 then
		return true
	end
	return false
end

Players.PlayerRemoving:Connect(function(player)
	local humanoidRootPartPos = player.Character:FindFirstChild("HumanoidRootPart").Position
	local inside = false
	for _, part in ipairs(game.Workspace:FindFirstChild("Interactions"):GetChildren()) do
		if part.Range then
			if checkIfPlayerIsInPart(humanoidRootPartPos, part) then
				inside = true
				print("Was in region")
				break
			end
		end
	end
	if inside == false then
		print("Wasn't inside region")
	end
end)

Parents of the interactions:
betterinter

And also, is there a way to detect if a player is in the region without having them leave the game? The reason I have a Range is that my goal is to have a gui that appears when they are in the region and then the gui would disappear when they leave the region.

1 Like

Alright, I kind of redid the function so that it loops through the whole Interactions Folder:

local function checkIfPlayerIsInPart(player)
	if player and player.Character and player.Character:FindFirstChild("Humanoid") then
		local hPartPosition = player.Character.HumanoidRootPart.Position
		for _, part in ipairs(game.Workspace:FindFirstChild("Interactions"):GetChildren()) do
			-- if part:FindFirstChild("Range") then
				local relPos = part.CFrame:PointToObjectSpace(hPartPosition)
				if math.abs(relPos.X) < part.Size.X * 0.5 and math.abs(relPos.Y) < part.Size.Y * 0.5 and math.abs(relPos.Z) < part.Size.Z * 0.5 then
					return true
				end
			--end
		end
	end
	return false
end -- Loops through Whole Interaction Folder

game.Players.PlayerRemoving:Connect(function(player)
	if checkIfPlayerIsInPart(player) then
		print("Was In Region")
		return
	end
	print("Was Not In Region")
end) -- On Player Disconnect

I wasn’t sure if you were intending to check whether players were only within regions with “Range” in them, so I commented that line of code in case that was your purpose.

The function checkIfPlayerIsInPart(player) takes in the player argument, so you can use this function anywhere in your script and it will detect whether or not the player is within a part by returning either true or false.

I’d like it to detect if they are in the “Range” part if that is possible. Because the interactions folder has parts that hold ClickDetectors which sizing is probably 2,2,2 or something along the lines of that.

Alright, in that case, you can remove the comments I made in the script.

local function checkIfPlayerIsInPart(player)
	if player and player.Character and player.Character:FindFirstChild("Humanoid") then
		local hPartPosition = player.Character.HumanoidRootPart.Position
		for _, part in ipairs(game.Workspace:FindFirstChild("Interactions"):GetChildren()) do
			    if part:FindFirstChild("Range") then
				local relPos = part.CFrame:PointToObjectSpace(hPartPosition)
				if math.abs(relPos.X) < part.Size.X * 0.5 and math.abs(relPos.Y) < part.Size.Y * 0.5 and math.abs(relPos.Z) < part.Size.Z * 0.5 then
					return true
				end
			end
		end
	end
	return false
end -- Loops through Whole Interaction Folder

game.Players.PlayerRemoving:Connect(function(player)
	if checkIfPlayerIsInPart(player) then
		print("Was In Region")
		return
	end
	print("Was Not In Region")
end) -- On Player Disconnect

I’m not sure what is going on, but it’s still printing Was Not In Region Here’s a video of the process:

https://gyazo.com/627a610935fae0e02d0094799339cc35

The grey box is the Range.

If anyone else was wondering what the issue was:

The “Range” part was larger compared to the interaction part, and the function was detecting whether or not the player was within the interaction part rather than the range part.

2 Likes

Thank you for all your help again! Have a great rest of your day.

1 Like

There are MULTIPLE things wrong with your code. First, you did “if i == player.Name then”, when you should have done “if v.Parent == player.Name then”. That is because the variable, i, will return a number, when you want a string/object. This next one isn’t really a problem, but on line 3, I would say “(part directory)”. Also, I don’t know much abt RunService, but if it is like a loop, then you should have put the removing loop ABOVE the runservice loop. Sorry if I missed anything :slight_smile: