Stabilizing Hover


For whatever reason I cannot figure out how to keep this thing at a constant hover rather than this crazy bounce. Anyone handy with physics?

local Force = script.Parent.Part:GetMass() * game.Workspace.Gravity * 1.5

local SuspensionHeight = 5;

local function Lerp(a, b, t)
    return a * (1-t) + (b*t)

local function RayDown(Part)
	local Cast =,,-1,0).unit * SuspensionHeight);
	return game.Workspace:FindPartOnRay(Cast,script.Parent)

while true do
	local dt = wait()
	for _,v in ipairs(script.Parent:GetChildren()) do
		if v:FindFirstChild("Humanoid") then
			local Part,Pos = RayDown(v.Head);
			local CompressionRatio;
			if Part and Pos then
				CompressionRatio = (SuspensionHeight - (Pos - v.Head.Position).Magnitude)/SuspensionHeight
				CompressionRatio = 0;
			v.Name = string.format("%.2f",tostring(CompressionRatio));
			v.Head.VectorForce.Force =,Lerp(v.Head.VectorForce.Force.Y, CompressionRatio * (Force/4),.8),0)

Stabilize.rbxl (18.0 KB)


Have you tried adding a bodyforce that pushes upwards with the force of the equivalent of gravity * the part’s mass?

1 Like

That would just results an object that hover perfectly still till another force acts upon it.

Edit: would also fly infinitely upward as soon as one of the “Thrusters” got close to the ground.

1 Like

I’m confused. Isn’t that what you want? You stated a “constant hover”. Do you want a light bounce-like feature that looks like the car is moving slowly up and down?

1 Like

The goal is to simulate suspension by applying an upward velocity on 4 different corners of the object based on how high above the ground each corner is. My problem is that I cannot figure out how to stabilize and keep it from bouncing all over the place

1 Like

Why not use a bodygyro to keep it from spinning around, and a bodyposition to stabilize it? You can also use a bodyposition instead of a bodythrust (Message me on the devforum for more info on bodyposition instead of bodythrusts). And I haven’t the time to test a suspension with a bodyposition instead of a bodythrust because I only
just accomplished a simple system like this today. My system does not use raycasting either… It just uses ‘bottompart:GetTouchingParts()’. You can message me on the devforum, and when I have the time (Or if I am awake, and my suspension system is fully done lol) I will give you or @snorebear a copy so you may learn, and use it freely ;).


The only disadvantage of using Bodypositions instead of bodythrusts, is that they have lots of strength. For example: If you put a large part on the thruster, the thruster will act as if the part on top of it is is weightless. (That might be either the way bodypositions work, or because my bodyposition’s maxforce properti is being set to ‘inf’)


Appreciate the suggestion but there is a reason I am going for the “more complicated system”.


Well pretty much every high quality vehicle system from GTA to Jailbreak that is not over the top focused on physics calculations uses this method. It relies entirely on the physics engine and thus reacts to both expected and unexpected situations in a realistic manner.

Here’s a cool overview of the idea.


So then my system would be unrealistic?


I watched that video before and tried to apply it to Roblox and ended up having the same issues you have now. Hoping someone can aid you so they indirectly help me.


I used the following:
Damping = 2*math.sqrt(Stiffness)
to make it critically damped. We assume that mass of wheels is equal to 1 for simplicity.
It gave a perfect result.


What is CurrentDist, and LastDist, lastly what is delta?

1 Like

Having some difficulties implementing this using what you have given. Did you implement this with the given studio file or your own?


CurrentDist = The distance between the “Thruster” and the ground
LastDist = The distance between the “Thruster” and the ground the last time it was calculated
Delta = Time in-between those two calculations.


So that means the time between the last calculation and the current calculation?

1 Like

Yes, in my code you see I signify Delta as local dt = wait()


Also having difficulty implementing


dt is argument to the function in Runservice


CurrentDist is the current frame’s distance between the spring’s origin and the part below it.
LastDist is the CurrentDist of the last frame.
Using this avoids having to calculate the velocity using angular velocities off both the car’s axle and the hit part.
Delta is just the time difference between 2 frames.

@Spooks_HD @VineyardVine
I used a custom implementation. Just made a platform with a Root part in the center, welded 4 axles to it and binded the formula to Heartbeat for each axle.

Also, set the force to (0,0,0) when no surface is detected.