Check if all players are touching a Part

I copied this code from another post, refactored it, and implemented it into my game. I am trying to check if all players are touching the floor of an elevator before closing the doors and moving to the next level. This code does work, but not 100% of the time and I often have to spam click the elevator button / jump repeatedly for this to register.

local Players = game:GetService("Players")

local function all_players_are_in_elevator()
	local players = Players:GetPlayers()
	local touching_parts = elevator_floor:GetTouchingParts()
	
	for index, part in ipairs(touching_parts) do 
		if part.Parent:IsA("Model") then
			for i, player in ipairs(players) do 
				if player.Character == part.Parent then
					table.remove(players, i)
				end
			end
		end
	end
	
	if #players == 0 then
		return true
	else
		return false
	end
	
end

Is there a better way I can write this code so that it always works? I think that this is just not detecting the touching parts correctly. Alternatively, is there a better way to do this than to check if all players are touching the elevator floor?

1 Like
local Players = {}
coroutine.resume(coroutine.create(function()
	game:GetService("RunService").Heartbeat:Connect(function()
		for Index, Player in pairs(workspace:GetPartsInPart(script.Parent)) do
			local PlayerFromCharacter = game.Players:GetPlayerFromCharacter(Player.Parent)
			if PlayerFromCharacter and not table.find(Players,PlayerFromCharacter) then
				table.insert(Players,PlayerFromCharacter)
			end
		end
	end)
	
end))
while task.wait() do
	for Dex,Plr in pairs(Players) do
		local Char = Plr.Character or Plr.CharacterAdded:Wait()
		if Char:FindFirstChild("UpperTorso") then
			if not table.find(workspace:GetPartsInPart(script.Parent),Char.UpperTorso) then
				table.remove(Players,table.find(Players,Plr))
			end
		end
	end
end

I have tested this code many times and it hasn’t failed once. You just need to make a big block as the detector. The block needs to be tall enough to reach your upper torso.

2 Likes

Check this code once

local T1 = {}
local part = -- put the part here

local function all_player_are_in_elevator()
local In = true
for i, v in pairs(game.Players:GetChildren()) do
if table.find(T1, v.Name) == nil then
In = false
end
end
return In
end

part.Touched:Connect(function(v1)
if v1.Parent:FindFirstChild("Humanoid") ~= nil then
table.insert(T1, v1.Parent.Name)
end
end)

part.TouchEnded:Connect(function(v1)
if v1.Parent:FindFirstChild("Humanoid") ~= nil then
table.remove(T1, v1.Parent.Name)
end
end)

game.Players.PlayerRemoved:Connect(function(v1)
if table.find(T1, v1.Name) ~= nil then
table.remove(T1, v1.Name)
end
end)

and as @10kgoldxdrip said, make sure to keep the block big enough

1 Like

Put this script server side, as a child of the detecting block. Make sure the block is large enough that the player’s HumanoidRootPart can touch it when walking into the elevator.

The reason I added my post, even though others posted above me, is that in my code, by checking for the HumanoidRootPart, you make sure there are no false ‘Enter’ and ‘Leave’ detections by hands or feet getting inside or outside the hit box.
Also, when detecting the player, its best to use game.Players:GetPlayerFromCharacter, instead of checking for a “Humanoid”

local playerTouchingList = {}
local visual = script.Parent.Parent:WaitForChild("Visual")
local cf = visual.CFrame

function Check()
	for _,player in pairs(game.Players:GetPlayers()) do
		if playerTouchingList[player.UserId] == nil then
			return false
		end
	end
	return true
end

script.Parent.Touched:Connect(function(part)
	if part.Name == "HumanoidRootPart" then
		local player = game.Players:GetPlayerFromCharacter(part.Parent)
		if player then
			playerTouchingList[player.UserId] = player
			if Check() then
				print("EVERYONE IS HERE!")
			end
		end 
	end
end)

script.Parent.TouchEnded:Connect(function(part)
	if part.Name == "HumanoidRootPart" then
		local player = game.Players:GetPlayerFromCharacter(part.Parent)
		if player then
			playerTouchingList[player.UserId] = nil
		end	
	end
end)
1 Like

A better and more saleable way would be to dynamically add and remove Players from a PlayersTouching array and calling a function depending on when the Part starts or stops getting touched. That way things are bit more ergonomic.

local Players: Players = game:GetService("Players")

local Part: BasePart = workspace.Part

local PlayersTouching: {Player} = {}
local AllPlayersTouching: boolean = false


local function OnPlayersTouching()
	print("Start!")
end

local function OnStopTouching()
	print("Stop!")
end


Part.Touched:Connect(function(TouchingPart: BasePart)
	for Index: number, Player: Player in Players:GetPlayers() do
		if Player.Character and Player.Character.PrimaryPart and TouchingPart == Player.Character.PrimaryPart then
			table.insert(PlayersTouching, Player)
			
			-- Number of PlayersTouching == Number of Players! All Touching!
			if #PlayersTouching == #Players:GetPlayers() and not AllPlayersTouching then
				AllPlayersTouching = true
				
				OnPlayersTouching()
			end
			
			break
		end
		
		continue
	end
end)

Part.TouchEnded:Connect(function(TouchingPart: BasePart)
	for Index: number, Player: Player in Players:GetPlayers() do
		if Player.Character and Player.Character.PrimaryPart and TouchingPart == Player.Character.PrimaryPart then
			local Index: number? = table.find(PlayersTouching, Player)
			
			if Index then
				table.remove(PlayersTouching, Index)
				
				-- Number of PlayersTouching <= Number of Players! We Stopped!
				if #PlayersTouching < #Players:GetPlayers() and AllPlayersTouching then
					AllPlayersTouching = false
					
					OnStopTouching()
				end
			end
			
		end
	end
end)
2 Likes

That was what I just did, above your post :stuck_out_tongue: but its always good to get more than one perspective.

1 Like