Creating a Height-Based Fall Damage System (Using Velocity)

[EDIT] - Changed script to work 100% server side, fixed grammar
[EDIT 2] - Changed how falling is detected

Recently whilst looking on the internet for good, robust fall damage tutorials I realized that most if not all only kill or give a predefined set of damage that is not dependent on the height you fell from. So that’s what we’re going to be doing here!

This is available as an Experience to test it out


Setup
In ServerScriptService add a blank script, this is going to be our Fall Damage Controller (FDC) script
image

In StarterCharacterScripts add a local script, this is going to be our Fall Detector (FD) script
image

For testing purposes I will also add a TrussPart in the Workspace


Defining Variables
Before we start we also need to define the MinVelocity and the MaxVelocity. MinVelocity is the minimum required Velocity/Speed to trigger fall damage and MaxVelocity is the required Velocity to kill a player.

You can either use variables or attributes. For this tutorial we will be using the latter.

To add attributes to a script

  • Select the FDC script in ServerScriptService and click Add Attribute in properties
    image

  • In the pop up choose the type as number and Name as MinVelocity
    image

  • Repeat again for MaxVelocity

Set these values to whatever you want. A MinVelocity of 25 is recommended


Detecting a Fall

Now that we have our MinVelocity and MaxVelocity we can get to coding!

In our FDC script we need to define the Attributes we set eariler. If your using variables, replace these with normal variables

local MaxVelocity = script:GetAttribute("MaxVelocity")
local MinVelocity = script:GetAttribute("MinVelocity")

To detect our player falling we can wrap all of our code in a CharacterAdded event

game.Players.PlayerAdded:Connect(function(Plr)
  Plr.CharacterAdded:Connect(function(Char)
  --  All New Code goes in here
  end)
end)

Inside our event we want to detect if the Character’s “State” has changed

local Humanoid = Char.Humanoid
local HumanoidRootPart = Char.HumanoidRootPart

Humanoid.StateChanged:Connect(function()
end)

When it’s changed we need to get our HumanoidRootPart’s Velocity, and invert it so it’s a positive number

local PlrVelocity = HumanoidRootPart.Velocity.Y
PlrVelocity *= -1

After we’ve gotten the Player’s velocity we’re going to do two checks

  • Player Velocity is greater than MaxVelocity (Yes - Kill them | No - Continue)
  • Player Velocity is greater than MinVelocity (Yes - Take Damage | No - Do Nothing)
if PlrVelocity > MaxVelocity then
	Humanoid.Health = 0
elseif PlrVelocity > MinVelocity then
	Humanoid.Health -= PlrVelocity / 2
end

Your full script should look like this

local MaxVelocity = script:GetAttribute("MaxVelocity")
local MinVelocity = script:GetAttribute("MinVelocity")

game.Players.PlayerAdded:Connect(function(Plr)
	Plr.CharacterAdded:Connect(function(Char)
		local Humanoid = Char:WaitForChild("Humanoid")
		local HumanoidRootPart = Char:WaitForChild("HumanoidRootPart")

		Humanoid.StateChanged:Connect(function(OldState, NewState)
			local PlrVelocity = HumanoidRootPart.Velocity.Y
			PlrVelocity *= -1

			if PlrVelocity > MaxVelocity then
				Humanoid.Health = 0
			elseif PlrVelocity > MinVelocity then
				Humanoid.Health -= PlrVelocity / 2
			end
		end)
	end)
end)

Print the Player’s velocity and change values as need


Conclusion

That’s the end of the tutorial! If anything doesn’t work try and debug it if you can, if you can’t post in the comments!

This is my first ever post so constructive criticism is appreciated!

20 Likes

This is a very helpful script, I’m very enjoying this while reading

1 Like

Hi I just finished using your script and it works fine, but there’s a gap in your script, when I, for example, jump from a part 2 studs high, I take damage, even if I fall from a little part, I take damage, I suggest you try modifying the script and adding something that controls if the player is at a certain height from the ground, and if it is enough, give damage, other than that, it works perfectly :smiley:

That’s what the MinVelocity value controls. Around 15 or something is the velocity generated by a jump. Higher the MinVelocity, higher you need to fall from to take damage.

Oh ok, I had to put it at 40 to not take damage from jumping at about 7-10 studs from the ground :sweat_smile:

Ok but do you know if there’s a way of checking the player’s distance from the ground so you don’t have to make MinVelocity higher?

I’m sure it would be possible to do that based on the Velocity of the Player and Gravity in World Settings to find it out but not too sure about that. Either way you would need to get the velocity and this is much easier to maintain

server sided script from natural disaster survival

--Made by Stickmasterluke


local sp=script.Parent

local fatalthreshhold=400
local safethreshhold=65
local rate=1/22

local damage=0
local lastvelocity=0

while true do
	local delta=wait(rate)
	local t=sp:FindFirstChild("HumanoidRootPart")
	if t~=nil then
		local currentvelocity=(t.Velocity).magnitude
		local pain=currentvelocity*(rate/delta)-safethreshhold
		if pain>0 then
			damage=damage+(pain/(fatalthreshhold-safethreshhold)*100)
		elseif damage>0 then
			local h=sp:FindFirstChild("Humanoid")
			if h then
				h:TakeDamage(damage)
				damage=0
			end	
		end
		lastvelocity=currentvelocity
	end
end
2 Likes

This is really easily exploitable, I don’t see why you would need a remote event for implementing fall damage.

It’s as simple as doing this and now the player won’t take fall damage.

game:GetService("ReplicatedStorage"):WaitForChild("FallDamageTrigger"):Destroy
1 Like

Ok thanks for trying to help :smiley:

It’s better of making it a Server Side script by looping through the players in the game since this is can be exploited easily. This is a great tutorial for being your first ever one. Good job, I’m impressed.

How could you detect a StateChange server side? I tried wrapping it in a PlayerAdded event but then the fall damage only occurred once. I’ll do some testing when I come back and if it works reliably I’ll edit the OP

When I tried to do it 100% server-side it didn’t seem to work reliably. Will test and update as necessary!

After half an hour of debugging it’s now fully server-side and more reliably checks for StateChanges!

1 Like