How to calculate frame independent car physics

Some background information first

suspension difficulties

When testing my car chassis system with a frame unlocker I’ve been noticing that the car accelerates a lot faster, and this makes sense because I’m calculating the force in the heartbeat function which is tied to the game’s framerate, in turn affecting the car physics as if the game is running higher than 60 fps the forces are being applied too quickly (sorry my drawing skills are terrible)

and if the game is running slower than 60 fps the forces are being applied too slowly.

For handling suspension, I’ve been trying to use a delta time ratio method (dt*60) to apply the appropriate forces using math to the car so the dampened harmonic oscillators do not become unstable and in turn flip and bounce the car around. This method has had varying degrees of success and could be improved upon.

Acceleration problems

Another issue is that the car accelerates too fast when there is a higher framerate because the driving force is also calculated through heartbeat.

as seen here (360 fps gameplay):
9338ef0f3219696183e774660cee6aaa
we can compare this to the 60 fps gameplay and see a noticeable difference

as seen here (60 fps gameplay):
b1d74461d3528f69de0116884f91cf70

My actual question

What can I do to resolve this issue, I’ve been at it for days but I still cannot think of a way to make the forces I am calculating frame independent.

Here I’ve put the force calculation code

Wheel.SpringLength    = math.clamp(Wheel.Raycast.Distance - Config.WheelRadius, 0, Config.MaxSuspensionLength)
Wheel.StiffnessForce  = Config.SpringStiffness * (Config.MaxSuspensionLength - Wheel.SpringLength)
Wheel.DamperForce     = Config.DamperStiffness * ((Wheel.SuspensionLength - Wheel.SpringLength)/FixedDeltaTime)
Wheel.SuspensionForce = Vector3.yAxis * (Wheel.StiffnessForce + Wheel.DamperForce)
		
Wheel.Velocity     =  Wheel.RotationOnlyWheelDirectionCFrame:ToObjectSpace(CFrame.new(self.Chassis:GetVelocityAtPosition(Wheel.Raycast.Position)))
Wheel.XForce       =  Wheel.RotationOnlyWheelDirectionCFrame.RightVector * -Wheel.Velocity.X * Config.WheelFriction
Wheel.ZForce       =  Wheel.RotationOnlyWheelDirectionCFrame.LookVector * Wheel.Velocity.Z * Config.WheelFriction/10
Wheel.DriveForce   =  Wheel.RotationOnlyWheelDirectionCFrame.LookVector * self.VerticalMove * Config.Torque
Wheel.GravityForce =  workspace.Gravity * Wheel.Raycast.Normal
		
Wheel.WheelForce = Wheel.SuspensionForce + Wheel.DriveForce/DeltaTime + Wheel.GravityForce/FixedDeltaTime + Wheel.ZForce/DeltaTime + Wheel.XForce/DeltaTime

You may’ve noticed a variable named FixedDeltaTime this is the aforementioned delta time ratio it is calculated like so:
local FixedDeltaTime = 60*DeltaTime

Anyways, I am multiplying all forces by DeltaTime which is clearly a problem but multiplying them by the FixedDeltaTime (which is actually a terrible name now that I think about it, because its not fixed at all but really just a ratio) is basically just multiplying by an insanely high number because any DeltaTime value is a lot smaller than 1.

Regardless, any help on the topic would be greatly appreciated, thank you!

2 Likes

Yeah dividing by delta time with high FPs will definitely get you a high value as you described, maybe even close to infinite.

Is this being applied to a physics constraint like vector force?

If so then I don’t think you need to do deltatime just let the Roblox physics engine handle it.

Otherwise you could try clamping delta time or use math.min to prevent deltatime from going too low which causes high acceleration/force values.

Maybe use os.clock() as another delta time measuring method?? But it should be the same with heartbeat.

There is also workspace: Get real physics fps which you should check out maybe.

Thank you for the response, but while delta time is a part of the problem I don’t believe the way of measuring it is wrong, Something to note is that the code is calculating impulses. If we didn’t include the division of delta time, the vector forces acting as the wheels are already creating a force applied over time so if we set the vector force to the calculated impulse it would be way too large of a force and would send the car flying into the atmosphere, to combat this I convert the impulse force to a force more suitable for being applied over time hence Wheel.DirveForce/DeltaTime

Im at work right now but cant give you a thorough answer but, i think what you are looking for is force/time times the change in time. So for example, if you apply 200 force for 1 second and the change in time is .5 seconds then you multiply 200 * .5 to get a force of 100. I think what you are doing wrong is dividing instead of multiplying.

1 Like

Your response while not being the exact answer actually inspired me to try something which in the end worked. So instead of trying to replace delta time with FixedDeltaTime (the deltatime ratio) I instead just did this: Wheel.DriveForce/DeltaTime*FixedDeltaTime so I could get the 60fps force required to lift the car and just increase or decrease the force depending on the framerate by multiplying by the delta time ratio

Thank you guys for the help!

1 Like

Doesn’t that just cancels out delta time?

FixedDeltaTime = 60*DeltaTime

Wheel.DriveForce/DeltaTime*60*DeltaTime

Wheel.DriveForce*60

I bet this has the same effect