Car Suspension (Scripted)

The awesome cars in the labs were made by @NWSpacek and kindly given to me, although I have since developed my own versions to use.

As far as I can remember the code works like this:

  1. Raycast from each thruster in the corner of the chassis
  2. Calculate the upwards force in each thruster from the length of the raycast, use either the code already in it or Oseday’s. Probably use Oseday’s, there’s a few problems in Roblox’s code if the car isn’t level.
  3. Change the wheel weld (the wheels are concollide off) using the raycast length to appear to be touching the surface of the ground.
  4. I use BodyThrust for propulsion and turning.
10 Likes

AH! So that’s how it works! I didn’t realise the wheels were cancollide off! That makes so much sense now!

With the wheels being cancollide off, it’s all based on thruster work which makes the thruster value easily able to act as if the wheels are cancollide on.

I will probably experiment with @Oseday’s Spring Physics as I think it looks cool too. I just wanted to understand exactly the process to make it work so that the rest is easier to understand.

I appreciate the help you’ve given me @madattak @Oseday. I think my next goal is to try and somehow have a go at making those wonderful hover cars that @NWSpacek made.

6 Likes

Good lord what is happening in there! Why not just use the PrismaticConstraint?

1 Like

Using scripts to simulate your springs

  • Uses far less resources
  • Done right, is far less prone to bugging out
  • Provides greater control of behaviour to the creator

Edit: Woops, first accidental necro bump I’ve done for a while. Teaches me to touch that ‘suggested topics’ list!

2020 Edit: For future reference, improvements to Roblox’s physics mean constraint vehicles are now likely to be a lot more stable and less likely to bug out and than code springs.

12 Likes

Hi, I know this is old Thread, but Looking at your code, I’m having trouble to understand How applying same force to wheel and car should work.

I opened new thread about same topic here. I’m having trouble figuring out, exactly how should I handle constraints and Forces. I’ve made hovercar and it works great, but making normal vehicles I find confusing. Too many constraints .

3 Likes

It’s exactly the same as a hover car, but you create cancollide off wheels, weld them to the thrusters, and change the C0 of the weld every frame so that they appear to be touching the ground.

3 Likes

How exactly would I change C0? I mean based on what? distance between the ground and car?

1 Like

Here’s what I’ve achieved so far:
Car.rbxm (14.7 KB)
With local script it doesn’t work as it would with server script and I don’t like it, but here it is.
But it’s still awful with serverScript.
Also I’m wondering how are you going to account for friction while driving the car.

You’ve got to code the friction mechanics yourself. If you’re not experienced with scripting in Roblox I would recommend searching for a constraint chassis instead (For example, doing a quick search of the devforum gave this: [Update] Constraint Chassis) as while I do firmly believe that scripted suspension vehicles are better overall, they take a lot of time and experience to make them work to a high quality.

1 Like

How can I prevent this from happening?

it sort of stutters and doesn’t tilt enough

local X = 6 --height
local K = 2000    
local B = 300


local y = i.Part.Position.Y     
local V = i.Part.Velocity.Y

local x0 = (y - hit_position.Y)

ST.d2x = ST.dx 
ST.dx = X-x0

local c = 2*math.sqrt(Part.Parent.Parent.Engine:GetMass() * K)

f = K*(X-x0)- ((X-x0)-ST.d2x)*c - B*V

this is how I calculate force. The result often is not enough to push car up so I multiply it by 4 and I believe this causes stuttering, but otherwise I don’t know how to calculate the force. I’ve tried many things. Changing x0, changing ST.dx to y position instead of X-x0 and other things, but haven’t solved it. My hovercar with same formula works great, So I assume it has something to do with the wheels.

Note:Part is edge thruster

Part.Weld.C1 = CFrame.new(0, math.abs((y - hit_position.Y) - i.Wheel.Size.Y/2), 0)
2 Likes

wouldn’t it be better to raycast down from the thrusters perspective?

so instead you would do

ray.new(thruster.position, - thruster.CFrame.upVector * height)

(I accidently pushed Shift+Enter and posted early.)

1 Like

This simply doesn’t work because suspension height is an integer, not a vec3.

1 Like

it would work, It would multiply the vector3 by the integer. I’m bad at explaining so just test it in studio for a more clear result.

For a good example of how this sort of stuff works, I have a file that features a custom physics engine and all the necessary bits and pieces to create a fully working vehicle (Including suspension)

You can look more into how suspension is handled through the function ‘bk’ in game.ReplicatedStorage.Module.Chassis (Line 526)

I am doing that currently. It’s not raycasting problem, the problem is that not enough force is applied to achieve proper tilt on rough terrain

You might want to check out the link I’ve posted above, it may help out with what you are trying to achieve here.

It’s just that there’s too many variables and it’s hard to follow. The formula I’ve posted above works perfect on hovercar but stutters on normal car as you see. Also normal car needs to tilt more than hovercar to look more realistic so it has to calculate enough force so that only one or two thrusters are able to tilt entire car

What’s your framerate when testing it on the normal car? I see no code calculating the force based on user framerate which would result in stutters at low frames.

I had to deal with this for a while, and am pretty satisfied with how I have it working now

Where can I see correct framerate

I suggest trying out my system for solving suspension, I can try to simplify it here

--I normally set Stiffness to 3, seems to be pretty good in most use cases
--Thruster is the part the wheel is held onto, the part that holds the BodyThrust
--aj is the delta between the current time and the last time this function has been ran.
-- helps ensure it will run well on all devices.
	local force = Mass * Stiffness--(O.Suspension * math.min(1,(1/aj)/60))--(O.Suspension * 60/((1/aj)))-- O.Suspension
	--print(math.min(1,(1/aj)/60))
	local damping = (Mass * Stiffness) * 1/(1/aj)--0.01--force / Bounce
	local hit, position = ray.new(Thruster.Position, Thruster.CFrame:vectorToWorldSpace(Vector3.new(0, -1, 0)) * Height)
	local thrusterHeight = (position - Thruster.Position).magnitude
	if hit and hit.CanCollide then
		--If we're on the ground, apply some forces to push the wheel up
		BodyThrust.force = Vector3.new(0, ((Height - thrusterHeight)^2) * (force / Height^2) * math.min(1,(1/aj)/60), 0)
		local thrusterDamping = Thruster.CFrame:toObjectSpace(CFrame.new(Thruster.Velocity + Thruster.Position)).p * damping-- * 1/(1/aj)
		BodyThrust.force = BodyThrust.force - Vector3.new(0, thrusterDamping.Y * math.min(1,(1/aj)/60), 0)
		BodyThrust.Location = Vector3.new(0,1,0)--b8.CFrame.upVector
	else
		BodyThrust.force = Vector3.new(0, 0, 0)
	end
3 Likes