I have a script that tells me whenever a player is touching the ground or not, but it’s not working as desired. Here’s my script:
local Players = game:GetService("Players")
local CollectionService = game:GetService("CollectionService")
local grounds = CollectionService:GetTagged("Ground")
Players.PlayerAdded:Connect(function(plr)
local folder = Instance.new("Folder")
folder.Parent = plr
folder.Name = "Folder"
local isOnGround = Instance.new("BoolValue")
isOnGround.Parent = folder
isOnGround.Name = "isOnGround"
isOnGround.Value = false
end)
for i, v in pairs(grounds) do
v.Touched:Connect(function(part)
local char = part.Parent
local hum = char:FindFirstChild("Humanoid")
if hum then
local plr = Players:GetPlayerFromCharacter(char)
local folder = plr.Folder
local isOnGround = folder.isOnGround
isOnGround.Value = true
print("isOnGround = true")
end
end)
v.TouchEnded:Connect(function(part)
local char = part.Parent
local hum = char:FindFirstChild("Humanoid")
if hum then
local plr = Players:GetPlayerFromCharacter(char)
local folder = plr.Folder
local isOnGround = folder.isOnGround
isOnGround.Value = false
print("isOnGround = false")
end
end)
end
But here’s the output window after just walking a few studs:
The player is walking on the ground, so the status shouldn’t be constantly changing. I tried making the part that qualified as ground thicker, and it still did this. How do I fix this?
A better, more consistent/reliable way of checking if a player is grounded is to check if their HumanoidStateType is NOT falling. To do this in a script just do: if Humanoid:GetState() ~= Enum.HumanoidStateType.Falling then you should run the code you only want to run between this statement and a end. Also, using this method you won’t have to have a isGrounded value in your player, as you can just use that if statement in your scripts
Unfortunately, this wouldn’t work because there are things above ground that you can stand on, and I don’t want that to count as standing on the ground.
local Module = require(game.ServerScriptService.Zone)
local NewZone = Module.new(BasePart)
NewZone.playerEntered:Connect(function(Plr)
print(Plr.Name.. " has entered the zone!")
end)
NewZone.playerExited:Connect(function(Plr)
print(Plr.Name.. " has exited the zone!")
end)
local Players = game:GetService("Players")
local CollectionService = game:GetService("CollectionService")
local RunService = game:GetService("RunService")
local grounds = CollectionService:GetTagged("Ground")
Players.PlayerAdded:Connect(function(plr)
local folder = Instance.new("Folder")
folder.Parent = plr
folder.Name = "Folder"
local isOnGround = Instance.new("BoolValue")
isOnGround.Parent = folder
isOnGround.Name = "isOnGround"
isOnGround.Value = false
local function CheckIfOnGround()
local onGround = false
for i, Parts in pairs(grounds) do
local PartsInRegion = workspace:FindPartsInRegion3(Region3.new(Parts.Position - (Parts.Size / 2), Parts.Position + (Parts.Size / 2)), nil, math.huge)
for i, Parts in pairs(PartsInRegion) do
if Parts.Parent then -- useless line
local PlayerFound = Players:GetPlayerFromCharacter(Parts.Parent)
if PlayerFound and PlayerFound == Player.Name then
onGround = true
break
end
end
end
end
isOnGround.Value = onGround
end
RunService.Stepped:Connect(CheckIfOnGround)
end)
Sadly, I don’t think it will work because after doing some reading on RunService.Stepped, this code will run tens of times per second, causing the game to be very laggy.
Actually, you can make proper use of them if you combine them with a table and only use them for parts that have a static network ownership. It’s kind of tricky, though.
Also it’s not a bad idea to bind spatial queries to Touched and TouchEnded so that you don’t have to run the queries in a loop.