How to Detect When a Player Is Falling

Currently I’m creating a custom animation script and have gotten to animating when the player is falling.

Code

humanoid.FreeFalling:Connect(function(active)
	if active == true and not fall.IsPlaying then
		idle:Stop()
		walk:Stop()
		jump:Stop()
		climb:Stop()
		fall:Play()
	end
end)

The falling animation plays when the player is falling, but also when the player is jumping. I thought the FreeFalling event detected when the player is actually falling and not when the player is jumping.

Does anyone know the solution to this?

3 Likes

Hey!

If you wanna change the falling animation, just copy the animate script inside the player while playing in studio, paste it into StartCharacterScripts and change the ID Values inside the script and values to your animation ID.

Also, the Jumping animation is different to the Falling one, since you jump, and then because you are in the air, the falling animation plays.

I used to do it that way but ran into something that made me decide writing my own animation script is best.

I’ll restate the problem more clearly. I have the Jumping event to fire when the player jumps, which makes the jumping animation play. This all works when I don’t include the FreeFalling event in the script. However, when I add in the FreeFalling event, it doesn’t fire when the player is falling, but at the same time the player jumps.

To put this in an example, I have added a print statement to run whenever the FreeFalling event fires and another one for when the Jumping event fires. I’ve noticed that this print statement runs at the same time the jumping event print statement does. I’m not sure if I should be using a different method to detect if the player is falling or if there’s a humanoid event that I’m not aware of.

You can try using raycasting with this to see if the height is high enough.

local maxHeight = 50
local plr = game.Players.LocalPlayer --Local script right?
humanoid.FreeFallint:Connect(function(active)
  if active == true and not fall.IsPlaying then
     local ray = Ray.new(plr.Character.HumanoidRootPart.Position,(Vector3.new(plr.Character.HumanoidRootPart.Position.X,0,plr.Character.HumanoidRootPart.Position.Z).unit * maxHeight) --were casting a unit ray
    local part,pos = workspace:FindPartOnRay(ray,plr.Character,false,false)
    if part then --check if theres a part to see if its high enough because if theres no part from the unit then means its high
      --play fall animation

You can search the wiki about raycasting and unit if you wish to learn more, the code basically casts a ray as long as 50 studs(i think its studs) and if the 50 studs doesnt touch anything then it means its high.

I’ve tried the raycasting thing and sadly it doesn’t work. Then I tried a bunch of other things for raycasting and it still didn’t work. However, I’ve figured something else out!

I calculated how long it takes the player to reach its max jump height (read this article to see how to calculate how high your player can jump). Knowing how high my player can jump allowed me to determine approximately how long it takes them to reach that height. My player can jump 6.25 studs high (my gravity is different) so I placed a part 6.25 studs away from a rig’s head. Then I had a local script store tick() in a variable whenever the player jumped. When the player’s head touched the part, an event fired, subtracting the current tick() from the stored tick(), and then printing this out. This was equal to approximately 0.17 seconds.

Now back to the animate script. I created a value called jumped, and made it equal to false. Whenever the player jumps, this gets set to true. When the FreeFalling event fires, I create a variable to hold the current tick() and then check if FreeFalling is active. If it is, then check if jumped is true, which if it is, set it now to false, and wait until tick() - the stored tick() >= 0.17. Then the fall animation will play.

To handle when the player falls off a part, I have an else statement if jumped was not true, allowing the fall animation to play.

Here is the code in case anyone wants it:

--Player Components
local player = game.Players.LocalPlayer
local character = player.Character
local humanoid = character.Humanoid

--Animatons
local idleAnim = script:WaitForChild("IdleAnim")
local walkAnim = script:WaitForChild("WalkAnim")
local jumpAnim = script:WaitForChild("JumpAnim")
local fallAnim = script:WaitForChild("FallAnim")
local climbAnim = script:WaitForChild("ClimbAnim")

local idle = humanoid:LoadAnimation(idleAnim)
local walk = humanoid:LoadAnimation(walkAnim)
local jump = humanoid:LoadAnimation(jumpAnim)
local fall = humanoid:LoadAnimation(fallAnim)
local climb = humanoid:LoadAnimation(climbAnim)

--Control Values
local jumped = false

humanoid.Running:Connect(function(speed)
	if speed > 0.001 and not walk.IsPlaying then
		idle:Stop()
		jump:Stop()
		fall:Stop()
		climb:Stop()
		walk:Play()
	elseif speed < 0.001 then
		walk:Stop()
		jump:Stop()
		fall:Stop()
		climb:Stop()
		idle:Play()
	end
end)

humanoid.Jumping:Connect(function(active)
	if active == true and not jump.IsPlaying then	
		jumped = true	
		idle:Stop()
		walk:Stop()
		fall:Stop()
		climb:Stop()
		jump:Play()
	end
end)

humanoid.FreeFalling:Connect(function(active)
	local start = tick()
	if active == true and not fall.IsPlaying then
		if jumped == true then
			jumped = false
			repeat wait() until tick() - start >= 0.17
			idle:Stop()
			walk:Stop()
			jump:Stop()
			climb:Stop()
			fall:Play()
		else
			idle:Stop()
			walk:Stop()
			jump:Stop()
			climb:Stop()
			fall:Play()
		end			
	end
end)

P.S. I excluded the climbing event because I haven’t scripted it yet.

5 Likes