Help with Part.Touched and Part.TouchEnded

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?

1 Like

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

Note: make sure you define Humanoid somewhere

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.

1 Like

Does anybody have any other ideas?

use RunService.Stepped and check if the player is in the part using workspace:FindPartsInRegion3

Touched and TouchEnded is bad

Don’t use FindPartsInRegion3 because it is deprecated. Use OverlapParams instead of the deprecated function.

Im not sure if this is what you want. But you could use a Region3. Id recommend ZonePlus since it makes creating Region3’s/Zones

easier(ZonePlus v3.2.0 | Construct dynamic zones and effectively determine players and parts within their boundaries)

Its pretty easy to use. Heres an example:

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)

@BirdieI90 @334901766 How would I use RunService.Stepped and OverlapParams to accomplish what I want?

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)

I don’t know if it works

1 Like

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.

No, this runs every frame and has little to no affect on game lag, unlike while loops.

1 Like

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.