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?
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.
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
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)
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)