The problem I am facing is if you touch the part, it will go “Players: 1 / 8” but if you move, while still inside the part, it will drop to 0 /8, then back to 1 /8. This is due the TouchEnded firing (as a part of the body is obviously moving)
However I want it to stay 1 / 8 until my player actually leaves the area. I was thinking of Region3, however I want to use a circle area, and not a square based area.
-- Player has touched the 'Play' area
local function PlayTouched(hit)
local Character = hit.Parent
if not Character then return end
local Player = Players:GetPlayerFromCharacter(Character)
if not Player then
Character = hit.Parent.Parent
Player = Players:GetPlayerFromCharacter(Character)
if not Player then return end -- Player officially don't exist
end
if table.find(WaitingPlayers, Player) then return end -- Player already in this table
table.insert(WaitingPlayers, Player) -- Add Player to WaitingPlayers
UpdateDisplay("Players: " .. #WaitingPlayers .. " / 8") -- Update the Display
end
local function PlayUntouched(hit)
local Character = hit.Parent
if not Character then return end
local Player = Players:GetPlayerFromCharacter(Character)
if not Player then
Character = hit.Parent.Parent
Player = Players:GetPlayerFromCharacter(Character)
if not Player then return end -- Player officially don't exist
end
-- See if player was in the table
local Index = table.find(WaitingPlayers, Player)
if not Index then return end
table.remove(WaitingPlayers, Index) -- Remove Player from WaitingPlayers
UpdateDisplay("Players: " .. #WaitingPlayers .. " / 8") -- Update the Display
end
Play.Touched:Connect(PlayTouched)
Play.TouchEnded:Connect(PlayUntouched)
If it’s a circle area, you could use magnitude and a while/heartbeat loop. A magnitude is to check the distance between the player and the center of the circle. If your area is a flat circle and not a sphere, you should make sure when calculating the magnitude that both the y values in both the vectors are the same.
You should be able to do a compromise then, use a touched event to start the detection then use the various area checking methods as @Tommybridge mentions in order to consistently check if the player is still touching/on the part. Get touching parts should be an alternate checking method but I haven’t tested it out.
The issue here isn’t your code, it’s touched being unreliable as always, say for example a player is faster than a frame or constantly jumping, touched will be triggered and gets buggy.
I’d suggest using another method, also heartbeat loops do not lag your game if that’s the issue, or at least if you’re doing checks on the client.
This is all purely server based. I don’t want to rely on client for this, as I feel it’d just add an unnecessary check on the server, when I can just do it all on the server easily.
Well, speaking of “dozens of loops” and “lag”, you’re really putting a heavy info-passing on the server at this point if you do everything on it, it’s better to leave the check on the client to avoid server-lag and have it all rely depending on client’s machine.
But Heartbeat is a function that’s apart of Rlua, won’t cause lag since its itself attached to the game.
Then I’d have to do client-server-client requests, which aren’t immediate in action, and can sometimes take a second or two before stuff happens. I also don’t want to create a remote event for the pure point of this 1 part being touched.
I actually made a post on this same problem like this a bit ago. Here:
local function GetTouchingParts(part)
local connection = part.Touched:Connect(function() end)
local results = part:GetTouchingParts()
connection:Disconnect()
return results
end
local myPart = -- Path in workspace to the part to be checked
local player = -- Path in workspace to the player to be checked for
while true do
local touchingParts = GetTouchingParts(myPart) -- Returns a table with all touching parts
for i, v in pairs(touchingParts) do
if v.Parent == player then
-- Do whatever you'd like
end
end
end
It’s still possible to do this with Touched/TouchEnded in an event-based way:
local part = workspace.Part
-- array of players currently touching this part
-- manipulated with table.find and table.remove because it's guaranteed not to grow larger than 100 players
local playersTouching = {}
function getPlayerFromRootPart(part)
return part.Name == "HumanoidRootPart" and game.Players:GetPlayerFromCharacter(part.Parent)
end
function onTouch(part)
local player = getPlayerFromRootPart(part)
if not player then return end -- do nothing if this isn't a player's rootpart
if table.find(playersTouching, player) then return end -- player somehow triggered Touched while still touching the part
table.insert(playersTouching, player) -- player is now in the list of touching players
-- your code that should run when player enters the region here
print("Entered", player)
end
function onTouchEnded(part)
local player = getPlayerFromRootPart(part)
if not player then return end
local index = table.find(playersTouching, player)
if not index then return end -- player somehow triggered TouchEnded without having touched the part
table.remove(playersTouching, index)
-- your code that should run when player exits the region here
print("Exited", player)
end
part.Touched:Connect(onTouch)
part.TouchEnded:Connect(onTouchEnded)
(itself an adaption of something I posted in another thread)
This code only tracks HumanoidRootPart because there’s only one of it in a character. When you want the script to activate on any body part coming in contact with the region, you have to keep track of every part of the character and remove the player when all of its parts have exited. It’s also possible to just keep a count of the parts of the player, but that’s likely to mess up when a part changes parents.
It’s probably possible to Touched, but not TouchEnded a part, and if that ever happens to you, have a script on a wait(2) loop use the above code to check which players are still actually near the part. It’s still looping, but it’s being done a hundred times less often.
You may want to use the Zone+ Module by ForeverHD. It’s the most well thought out and likely foolproof system to detect touch, which uses a combination of ray casting and region3.
Maybe use Region3?
Yes you have to check every second if someone is near, but its good because player (or object) does not have to move.
If its in Region you get its instance value.