I am trying to make a reliable fall damage script, so far I’ve had no luck. I’ve made several of my own and tried half a dozen i’ve found online. StateChange is most problematic because the player doesn’t always “land” but instead switches to running or runningnophysics
2 main issues that keep popping up:
It doesn’t work every time, depending on if the player jumped, was pushed etc.
if i give the player a jump boost and he jumps up high and lands on a part that is higher than the part he jumped from it still registers as if he fell and not jumped up, if it registers at all
If anyone has discovered a solution that solves these two problems please share, thank you for your time
Detect changes in the Y. Solves all of your problems here. If the Y before jumping was greater than the Y upon landing, then the character fell. Separate the different thresholds into different damage levels.
You could connect the .Touched event for each part parented to the character(.Touched apparently works on terrain, although I think it fires when the player touches water also). You could also check the Humanoid’s FloorMaterial, and if it’s set to “Air” then the character isn’t touching the ground.
Then for damage, you could take damage based on HumanoidRootPart’s Y velocity(only damages the player when he falls), or HumanoidRootPart’s Velocity.Magnitude(which would allow damage from the player moving at high velocities in other directions).
You can utilize the Humanoid.StateChanged event to achieve your goal. Every time if your humanoid state changes to freefall, you can get the y position once it changed, then once the state changes to Landed, you can get the Y value of the HumanoidRootPart when the Humanoid lands, and take the difference of the two Y values. Depending on the difference, you can scale your damage accordingly.
What I would do is do a combination of detecting velocity of the y axis of the torso and GetPropertyChangedSignal for FloorMaterial on the Humanoid. If the floor material is changed from air to some material and the velocity of the torso was some value then you could say they fell from a certain height.
You would then have to run something every frame(this wouldn’t be too bad, because there isn’t intense computing power going on):
1A. Check if player is off the ground via raycasting
1B. If player is not off the ground, repeat 1A until they are off the ground
2. Get the velocity of the player, whilst raycasting downwards equal to the velocity(so if the velocity is "0, 5, 0", you would rayacst "5" studs downwards)
3A. If it hits a part, wait for the player to hit the ground, then take corresponding damage
3B. If not, keep doing #2 until 3A is met
I made a fall damage script. It worked every time I tested it, and doesn’t damage a player when he falls into the water.
--height at which the player starts to take damage
local minimumDamageHeight = 20
--height at which the player takes maximumDamage damage
local maximumDamageHeight = 100
--if height exceeds maximumDamageHeight,
--player will take over maximumDamage damage
local maximumDamage = 100
local velocity
-- linear interpolation function
local function lerp(a,b,t)
return (1-t)*a+b*t
end
--inverse of lerp function
local function invLerp(a,b,v)
return (v-a)/(b-a)
end
--remaps value, used for max and min damage heights.
local function remap(iMin,iMax,oMin,oMax,v)
return lerp(oMin,oMax,invLerp(iMin,iMax,v))
end
-- fired when FloorMaterial changes
script.Parent.Humanoid:GetPropertyChangedSignal("FloorMaterial"):Connect(function()
--calculate fall height from velocity
local height = (velocity * velocity)/(2*workspace.Gravity)
--remap damage based on variables
local damage = remap(minimumDamageHeight,maximumDamageHeight,0,maximumDamage,height)
--prevent negative damage
damage = math.max(damage,0)
--apply damage
script.Parent.Humanoid:TakeDamage(damage)
end)
--fires before each physics update
game:GetService("RunService").Stepped:Connect(function(time,step)
--update velocity variable
velocity = script.Parent.HumanoidRootPart.Velocity.Y
end)
I put this in a LocalScript in StarterCharacterScripts.
It seems pretty easy for players to hack the client or the server(I’ve heard you can download programs to do it for you), so I don’t worry about it. In this case a client side script works better.
Probably the reason it doesn’t work in a server script is the .Stepped function. The server and client aren’t quite synced, so there might be a little delay(and so velocity is low by the time GetPropertyChangedSignal(“FloorMaterial”) gets fired.
The loop I use is called just before physics are calculated, so it is in sync. I tried getting the velocity only after an event was fired(tried multiple events), but it had already responded to collision and was set to 0. For fall damage, you need the velocity on the previous physics frame, which can’t be done with just events.