Fall damage system fails at high speeds

I’m trying to implement a fall damage system to my game. I would gladly use HumanoidStates to detect when the player hits the ground but sadly my game’s ragdoll system overrides a player’s HumanoidState with the Physics state every time they reach a certain velocity. I decided to use a method that casts a ray downward from the player’s HumanoidRootPart every frame and checks if the ray length is shorter than or equal to the player’s height. This works most of the time but starts failing when the player hits the ground with a very fast velocity. How can I fix this? Here is a simplified version of the script:

game:GetService("RunService").Heartbeat:Connect(function()
	if(canFall) then
		local humHeight = (0.5 * humRootPart.Size.Y) + hum.HipHeight + 1
		local yVelocity = humRootPart.Velocity.y
		if(yVelocity > 0 or math.floor(yVelocity) == 0) then
			return
		end
		yVelocity = math.abs(yVelocity)
		
		local rayOrigin = humRootPart.Position
		local rayDirection = Vector3.new(0, -500, 0)
		local raycastParams = RaycastParams.new()
		raycastParams.FilterDescendantsInstances = {char,debugFolder}
		raycastParams.FilterType = Enum.RaycastFilterType.Blacklist
		local raycastResult = workspace:Raycast(rayOrigin, rayDirection, raycastParams)
		if (raycastResult) then
			local hitPos = raycastResult.Position
			local distance = math.abs(humRootPart.Position.y - hitPos.y)
		
			if(yVelocity >= minVelocity.Value and distance <= humHeight) then
				canFall = false
				--Deal damage based on yVelocity
				wait(fallCooldownTime.Value)
				canFall = true
			end
		end
	end
end)

How about implementing fall damage by using velocity change instead of fall distance.
Make a script that compares the current y-velocity of the hominid with the velocity of previous frame. Then if the velocity change is over a certain threshold (make sure to get the positive of negative correct, otherwise it will damage the player on sudden upward acceleration too), apply damage.

local previous
function onUpdate(delta)
    if not previous then
        previous = currentVelocity
    else
       local diff = currentVelocity.Y - previous.Y
        if diff > threshold  then
            damagePlayer(diff)
        end
    end
end

Edit
Of course if you want if implement falldamage based on height, you could use the same concept to detect the start of fall ( check if the velocity if constantly increasing for several frames ) then apply damage when the velocity.Y decreases suddenly.

1 Like

Sounds like a more consistent method! I’ll try it out later. Also this is just a nitpick, but my current method doesn’t calculate damage based on falling distance—damage is based on the vertical velocity at the time of impact. I just didn’t include it in the code snippet because my issue is actually detecting the impact, not calculating the damage.

1 Like

I ended up using a modified version of your code that works much more consistently than my old method. Thanks!