More reliable alternative to humanoid.StateChanged?

Is there a more reliable way to detect if a player landed? I am currently using humanoid.StateChanged:

humanoid.StateChanged:Connect(function(new)
if new == Enum.HumanoidStateType.Landed then
print("blablabla")

This only detects the changed state like 50% of the time. I hope someone can tell me about how to fix this or if someone can tell me about an alternative :happy1:

The first parameter is the old state. The second one is the new state.

3 Likes

If you’re looking to tell when the player lands on the ground without using states, you can use raycasting to cast a ray directly downwards, checking if ground exists or not. When it doesn’t a frame before and exists this frame, the player landed.

No.

The new parameter is actually referring to the old state. You need to include a second parameter so you can refer to the new one.


https://developer.roblox.com/en-us/api-reference/event/Humanoid/StateChanged

You only used one parameter so of course it’s being treated as the old state.

2 Likes

Putting the ‘‘old’’ parameter there changed absolutely nothing, I am just trying to make it more reliable as the function itself works. It just does not work all the time for some reason

It’s only supposedly working “50% of the time” since the player would have to jump twice for there to be a previous input, which your callback to StateChanged would then detect.

Try something like

local function onChanged(old, new)
   if new == Enum.HumanoidStateType.Landed then
   print ("landed")   
   end
end

Humanoid.StateChanged:Connect(onChanged)

to actually check the current state.

It works almost 100% of the time adding a second parameter, perhaps there’s something wrong with your implementation.

You could try other alternatives if this is not what you want, such as casting a ray x studs below the character’s HumanoidRootPart to detect whether there’s a part underneath.

It doesn’t. I copied and pasted your exact script and it did not work 100% of the time:

I don’t know about the accuracy of StateChanged and or if you’re doing something wrong, but a less accurate (but perhaps more reliable) method would be to continually check the HumanoidRootPart’s velocity on the Y axis. If it changes from a negative value to at least zero, the humanoid just landed. It is still inaccurate because if a humanoid jumps from a great height and “bounces” on the ground, your “landed” action will perform multiple times for each bounce.

Don’t you want to use a LocalScript instead of a script to detect client input?
Use a LocalScript within StarterPlayerScripts or StarterCharacterScripts with that code and tell me how often it works.

Edit: Hard to assume errors without any context.

You can modify it to work within StarterCharacterScripts too and index the character differently if you want, regardless here’s the one I used within StarterPlayerScripts:

-- @ StarterPlayerScripts

local player = game.Players.LocalPlayer
local char = player.Character or player.CharacterAdded:Wait()

local humanoid = char:WaitForChild("Humanoid", 5)

local function onChanged(old, new)
   if new == Enum.HumanoidStateType.Landed then
   print("landed")   
   end
end

humanoid.StateChanged:Connect(onChanged)
2 Likes

Using a script in StarterCharacterScripts, you can try checking if the old state is Freefall. Looks like it works 100% of the time, at least for me. This entire method however only works if the fall is in the player’s control (e.g. not if the player gets flinged or knocked over). You might want to do a velocity check if your intended use case is a fall damage script.

Thank you, this seems to work all of the time. I have a velocity check already, the rest of the script is in place it was just this part I was having trouble with.

Sorry @sjr04 @XxELECTROFUSIONxX for being a bit unclear on what I wanted to achieve here.

1 Like