How do I take damage based on the velocity of an object?

I’m trying to make a script that deals damage when hit by an object. I wrote a simple script using the touched event with object.magnitude.

humanoid.touched:Connect(function(hit)
	local magnitude = hit.Velocity.Magnitude
	if magnitude >= 40 then
		humanoid:TakeDamage(magnitude/15)
	end
end)

It seems to work fine at first, but after some playtesting, I found out a few problems. When the player is standing on an moving object (for example a car), the player takes damage even when nothing is hitting them. Also, when the player is being flinged towards a wall, he takes no damage because the script only checks for moving objects. I’ve tried adding the velocity of the HumanoidRootPart to magnitude, then tweak the numbers, but now the player takes damage when starting to jump. Now, I’m stuck here and I have no idea what to do :sob:

Is there any way to fix this problem, or is there a more reliable way to deal damage to the player when hitting objects?

3 Likes

Well I think maybe the problem is about relative velocity. The hit.Velocity.Magnitude is the absolute velocity of the other moving part and what determines the actual damage should be relative velocity (at least in real life)
So, changing the second line to this should work:

local magnitude = (hit.Velocity - humanoid.Parent.HumanoidRootPart.Velocity).Magnitude

edit:
Also, if you don’t expect something like a player runs into a wall and take damage, just add an if statement before it:

if hit.Velocity.Magnitude == 0 then return end
local magnitude = (hit.Velocity - humanoid.Parent.HumanoidRootPart.Velocity).Magnitude

Sorry for the late reply. I tried your way, but it had the same problem with adding the velocity of HumanoidRootPart to it, which is the player takes damage when starting to jump.

I tried this too to prevent the jumping problem, but the problem with roblox physics is that sometimes an unanchored object moves a little when you jump on it. I then added a bound to it, but then I found out that when you push an unanchored object and then jump, you get damaged. When I increased the bound, falling objects sometimes don’t damage the player.

Well, my code is filled of little errors, I’m wondering now if there was a more efficient way to take hit damage other that the magnitude.

1 Like

The jumping problem is easy, because we can check if the other part is a child of the player’s character.

if(hit:IsDescendantOf(humanoid.Parent))then return end

You have to check it is a bullet hitting the player. The reason the player was taking damage when on a car is because the players parts are going to be touching the humanoid so doing something like this would help

humanoid.touched:Connect(function(hit)
    if hit.Name == "Bullet" then
...

No, It’s not because of player parts hitting themselves. When the player jumps on an anchored part, he doesn’t take damage. When the player jumps on an unanchored part, the part sometimes move because of weird roblox physics. The player takes a little bit of damage that corresponds to the magnitude of the velocity of the block.

I’ve thought of checking whether the player is standing on that part. I found a post on it, but it’s a bit too advanced.

You misunderstood me :sweat_smile:. I didn’t say that the object is a bullet. I’m making a game that simulates real life. You get damage when you get hit by moving objects, falling objects, flying objects, etc.

Well in this case you can replace the
if hit.Velocity.Magnitude == 0 then return end
into
if hit.Velocity.Magnitude < [put a minimum value here] then return end

if this is not suitable for your game context, maybe you can try adding a ignore list, or use raycasting.

well I’m not very sure if ray can precisely deal with this…

3 Likes

Yes. I’m not quite understanding the scripts people post above, because they are just as redundant in the sense that they don’t really work.

The best way of dealing damage is a raycast from the damaging object. Relying on physics will do you no good. However, if you want to do a velocity damage system, try:

--- function top
local vel0 = math.max(rootpart.Velocity.Magnitude,1)
local vel1 = math.max(otherpart.Velocity.Magnitude,1)
local damage = math.max((vel0/vel1 - (vel0*(vel1-1)) - 1) % 0.1,0) -- Deals int dmg
--- end

Not sure if that code works, but give it a try?
Btw, %0.1 means to take the decimals out of the number.

2 Likes

@Chrous_Pickaxe

Yes, I did try that, it works perfectly fine. Thanks!

@iGottic

This code doesn’t work. For some reason, the math keeps returning small decimal values.

I’m interested in raycasting. I’ve heard of it but never eally understood it. I’ll look into it and see what more I can learn. I’ll try to accomplish the hit damage thing with raycasts as a small challenge for myself :smile:.

1 Like

You mind find use of that :point_up:

1 Like

In addition, I have modified the code to make it not so small (?)

local vel0 = math.max(rootpart.Velocity.Magnitude,1)
local vel1 = math.max(otherpart.Velocity.Magnitude,1)
local damage = math.max((vel0/vel1 - (vel0*(vel1-1)) - 1),0)

Maybe another way of doing would be checking the Humanoid’s state using Humanoid:GetState() could work better?

I’ve uploaded a tutorial on it here