Alternative Approach to Fall damage system GONE WRONG

Hello, I recently made a pretty unnecessary fall damage system as I didn’t know .Velocity existed till researching today when I needed help.

Anyway the problem is that since I’m raycasting when the player is falling It’s tricky detecting when the players lands. I’ve tried getting the time when the player will land then damaging the player but that didn’t work out.

If there’s a way that I can keep this code and not re-code it that would be amazing

-- services

local Players   = game:GetService("Players")
local Workspace = game:GetService("Workspace")

-- constants

local MAX_MAGNITUDE,MIN_MAGNITUDE = 100,10

local VALID_TYPES = { -- this is the best way I can think of
	["Enum.HumanoidStateType.FallingDown"]  = Enum.HumanoidStateType.FallingDown,
	["Enum.HumanoidStateType.Flying"] 		= Enum.HumanoidStateType.Flying,
	["Enum.HumanoidStateType.Jumping"]      = Enum.HumanoidStateType.Jumping,
	["Enum.HumanoidStateType.Running"]      = Enum.HumanoidStateType.Running,
}

-- functions

local function GetArrivalTime(magnitude: number)
	local t = 0
	
	return t == -16 ^ 2 + magnitude
end

local function OnStateChange(player)
	local character = player.Character or player.CharacterAdded:Wait()
	
	local function ApplyForce(character)
		local RAYCAST_PARMS = RaycastParams.new()
			RAYCAST_PARMS.IgnoreWater = true
			RAYCAST_PARMS.FilterDescendantsInstances = {character}
			RAYCAST_PARMS.FilterType = Enum.RaycastFilterType.Blacklist
		
		local rayCast = Workspace:Raycast(character.PrimaryPart.Position,character.PrimaryPart.Position * Vector3.new(0,-1000,0),RAYCAST_PARMS)		
		if rayCast then
			local distance = (character.PrimaryPart.Position - rayCast.Position).Magnitude
			if rayCast.Instance then
				wait(GetArrivalTime(distance))
				local instanceMagnitude = (character.PrimaryPart.Position - rayCast.Position).Magnitude
				if instanceMagnitude < MAX_MAGNITUDE and instanceMagnitude >= MIN_MAGNITUDE then
					local desiredDamage = math.round(instanceMagnitude / MAX_MAGNITUDE * 100)
					if desiredDamage >= 10 then
						warn(desiredDamage)
						character.Humanoid.Health = character.Humanoid.Health - desiredDamage
					end
				elseif instanceMagnitude > MAX_MAGNITUDE then
					if character:FindFirstChild("Head") then
						character.Head:Destroy()
					end
				end 
			end
		end
		RAYCAST_PARMS = nil
	end
	
	if character then	
		if character:FindFirstChildOfClass("Humanoid") then
			character.Humanoid.StateChanged:Connect(function(oldState, newState)
				if newState == VALID_TYPES[tostring(newState)] then
					warn(newState)
					ApplyForce(character)
				end
			end)
		end
	end
end

-- initalize

Players.PlayerAdded:Connect(function(player)
	player.CharacterAdded:Connect(function()
		OnStateChange(player)
	end)
end)

This is now solved. If anybody is stumbling upon this what I did was create a new function which take the magnitude between the origin and the result from a raycast then used a little bit of Newtonian mechanics to get the arrival time aka the time they are going to touch the ground.

local function GetArrivalTime(magnitude: number)
	local t = 0
	return t == -16 ^ 2 + magnitude
end

or you can literally just use Enum.HumanoidStateType.Landed

1 Like

That wouldn’t work with what I have since I’m raycasting and initializing it would when the player lands would give me the distance after they fall so 0 (rounded). And if I had a connection to listen for the landed event then I would need to do a lot more things like inserting that players fall damage into an table then checking if theres a value in that table and then if it is I would damage them from there making me have to re-write my code a little bit