Problem with getting more accurate collision force

I’m trying to make a script that will get more accurate force for a vehicle damage system by checking the velocity before and after the collision and using the difference as the force.

It works fine if I move the part it’s in on the server but if the parts moved by a player in any way the force is always zero no matter how hard it hits something.

Script:

local Parent = script.Parent
local Velocity = 0
local ForceVelocity = 0
local Force = 0

game:GetService("RunService").Heartbeat:Connect(function()

	Velocity = Parent.AssemblyLinearVelocity.Magnitude
	
end)

Parent.Touched:Connect(function()
	
	ForceVelocity = Parent.AssemblyLinearVelocity.Magnitude
	
	Force = math.max(Velocity, ForceVelocity) - math.min(Velocity, ForceVelocity)

	print("Force: "..Force)

end)

Put the script in a ball or something and throw it around on the server and client and see what happens.

Why are there so many functions. Can’t you just do this:

local part = workspace.Part --The part

part:GetPropertyChangedSignal("AssemblyLinearVelocity"):Connect(function()
    print(part.AssemblyLinearVelocity.Magnitude) --The overall force
end)

I’m not sure if :GetPropertyChangedSignal() supports that property, so it might not work.

I have so many functions because this is just a test script to see if I can get more accurate force, so it just makes it easier to understand, I have tried using only velocity but the problem is it’s just checking the speed when it’s touched meaning if you drag the car across a wall the speed won’t change and the car will take a ton of damage, so I’m trying to get the velocity before the impact and after the impact then using the amount the part slowed down as the force, also :GetPropertyChangeSignal() doesn’t support velocity.

If you’re trying to use a crash system, then round up your velocity using .Magnitude and then set the velocity to 0 or decrease it, as soon as it collides with a part.

Remember to save the previous velocity, so when it does collide, you can use that velocity to calculate the damage.


Try creating a part A, and use the baseplate as the part B. You can test the velocity by dropping part A, unanchored, to the baseplate in different distances to see the printed value change:

local RS = game:GetService("RunService")

local partA = workspace.Part
local partB = workspace.Baseplate

local debounce = false

partA.Touched:Connect(function(otherPart)
    
    if debounce == false then debounce = true else return end
    
    if otherPart == partB then
        local velocity = partA.AssemblyLinearVelocity.Magnitude
        print(velocity) --Shows the current velocity before dividing it by 5
        velocity /= 5
    end
    
    task.wait(1)
    debounce = false
    
end)

Sorry if I explained this poorly, I’m not using a crash system I’m trying to make one.

I have a vehicle model with multiple parts like the bumper, hood, fenders, etc, I want each part to have health and a damage script that gets a force of some kind from the part it’s in when it hits something then removes the amount of force from the health, and if the health is <= to some amount then do something to the part like BreakJoints().

This is what I did in my game, and I used AssemblyLinearVelocity.Magnitude as the force, the problem with using it is its only getting the speed of the part not the force of the collision meaning if the health is 500 and the part is dragging against something at 100 velocity the touch event will fire constantly and every time it fires it will damage it by 100, but if I get the force before and after the touch I can use the amount it slowed down as the force to fix that.

Example of what should happen when dragging against a wall (Heaplash by @Ferghins): (35) Dragging - YouTube

Example of what happens in my game using AssemblyLinearVelocity.Magnitude: (35) Dragging2 - YouTube

The updated method of getting force (using the amount it slowed down) works great if I move the part in the server while playing, but if I move it with any sort of player input it stops working, like if I weld it to the front of a car and drive into something it prints 0 no matter what.

Example: (35) Problem - YouTube

The old method did not do this, I have tried using vehicles that don’t claim network ownership but it doesn’t work, the only reason for this happening I can think of is that VehicleSeat automatically claims network ownership.

You can just get the velocity and check if it has drastically decreased on a touched event.

Another thing to mention, don’t set the Touched events on the car, only on every single part of the map except the floor, you could use CollectionService for that.

You would want cars to have the network ownership set to the player, since you have full control of it, and it doesn’t lag.

If you are sure that you don’t want the client to control it, you could have used :SetNetworkOwnershipAuto(), but that doesn’t work. Right now there’s nothing you can do.

I do want the cars to have network ownership set and I’m not really sure if network ownership is causing the problem, it’s just the only thing I can think of at the moment.

I don’t really know what you mean by:

Also, I would like the script to be in the car, so I don’t have to put a script in every new part of the map I add.

I really appreciate you trying to help me improve the script, but I can try to do that on my own, I really just care about fixing this:

Also got more information on the problem, the velocity before and after the crash is normally correct but when the network ownership is claimed the before velocity’s loop is updating more meaning its updating fast enough where it ends up being almost the same as the after force but still not updating fast enough to be the exact same.

What I’m saying is when a car does touch a part, then you can check if the current velocity has been decreased a lot, usually indicating a full-stop crash:

local part = workspace.Part --Customise this
local velocity = part.AssemblyLinearVelocity.Magnitude

while task.wait() do
    
    if part.AssemblyLinearVelocity.Magnitude < velocity-5 then
        print("Crashed. Intensity: "..tostring(part.AssemblyLinearVelocity.Magnitude))
    end
    
    velocity = part.AssemblyLinearVelocity.Magnitude
    
end

Try to run studio instead of playing it, so you can control the part, fling it, and see what the crash detection does.

If it doesn’t work, then try decreasing the number in the if statement.

It works great but if you slow down the car fast enough it will have high force, I fixed that by adding a touch event, also the threshold number increases the amount of force meaning if I stop the car against a wall, it will constantly take at least 5 damage and if I delete the threshold, it gets rid of that problem but makes dragging a problem again, I tried fixing that by minusing the threshold from the force but now it sometimes prints negative and still does it.

Script:

local Parent = script.Parent

local Threshold = 5
local Velocity = 0
local Force = 0

game:GetService("RunService").Heartbeat:Connect(function()

	if Parent.AssemblyLinearVelocity.Magnitude < Velocity -Threshold then

		Force = math.round(Parent.AssemblyLinearVelocity.Magnitude - Threshold)

	end

	Velocity = Parent.AssemblyLinearVelocity.Magnitude

end)

Parent.Touched:Connect(function()
		
	print("Intensity: "..Force)
	
end)

If you’re able to slow down fast enough to detect a “crash”, then decrease the brake strength on the car, or make the threshold bigger.

I already managed to fix that by adding a touch event.

So what’s wrong then, it’s fixed?

No, it’s still doing this:

I can’t really think of a way to fix it.

Now that I look at this, you can just get every single part in your car model, and save a health attribute. Then, you can try using velocity to calculate the damage, and to decrease the health. If it does reach 0 health, then you can either try to unanchor it, or use the deprecated but still functional :BreakJoints() method.


Here’s how it looks:

local car = workspace.Car --The model

for _,part in pairs(car:GetDescendants()) do
	if part:IsA("BasePart") then
		
		part:SetAttribute("Health", part.Size.Magnitude/2) --Sets the health amount by part size
		
		part.Touched:Connect(function(otherPart)
			if not otherPart:FindFirstAncestor(car) then
				
				local velocity = part.AssemblyLinearVelocity.Magnitude
				part:SetAttribute("Health", part:GetAttribute("Health")-velocity)
				
				if part:GetAttribute("Health") <= 0 then
					part:BreakJoints()
					part.Anchored = false
					print("broken")
				end
				
			end
		end)
		
	end
end

Still no fix for this, maybe I’m just stupid but I’ve tried everything I can think of, the best I’ve gotten was switching the RunContext to client which just switched the problem to where the server would always print zero, but the client would work fine, I really don’t understand why this is happening, I would think the script would run the same on the server and client, only thing I could think of is if I’m using some code method that isn’t available on the client.