Car Suspension System Not working

I have been trying for a while to create a working suspension system for a car, but I just can’t seem to get it right. Here is the script:

 spawn(function()
        	game:GetService("RunService").Stepped:connect(function()
        		local equi = 3
        		local ray1 = Ray.new(game.Workspace.Model.ThrustFR.Position, game.Workspace.Model.ThrustFR.CFrame:VectorToWorldSpace(Vector3.new(0, -1, 0)*3))
        		local ray2= Ray.new(game.Workspace.Model.ThrustFL.Position, game.Workspace.Model.ThrustFL.CFrame:VectorToWorldSpace(Vector3.new(0, -1, 0)*3))
        		local ray3 = Ray.new(game.Workspace.Model.ThrustBR.Position, game.Workspace.Model.ThrustBR.CFrame:VectorToWorldSpace(Vector3.new(0, -1, 0)*3))
        		local ray4 = Ray.new(game.Workspace.Model.ThrustBL.Position, game.Workspace.Model.ThrustBL.CFrame:VectorToWorldSpace(Vector3.new(0, -1, 0)*3))
        		local hit1, position1 = workspace:FindPartOnRay(ray1, game.Workspace.Model)
        		local hit2, position2 = workspace:FindPartOnRay(ray2, game.Workspace.Model)
        		local hit3, position3 = workspace:FindPartOnRay(ray3, game.Workspace.Model)
        		local hit4, position4 = workspace:FindPartOnRay(ray4, game.Workspace.Model)
        		local height1 = game.Workspace.Model.ThrustFR.Position.Y - position1.Y
        		local height2 = game.Workspace.Model.ThrustFL.Position.Y - position2.Y
        		local height3 = game.Workspace.Model.ThrustBR.Position.Y - position3.Y
        		local height4 = game.Workspace.Model.ThrustBL.Position.Y - position4.Y
    		
    		local wheelHeight1 = game.Workspace.Model.WheelFR.Position.Y - position1.Y - (game.Workspace.Model.WheelFR.Size.Y/2)
    		local wheelHeight2 = game.Workspace.Model.WheelFL.Position.Y - position2.Y - (game.Workspace.Model.WheelFL.Size.Y/2)
    		local wheelHeight3 = game.Workspace.Model.WheelBR.Position.Y - position3.Y - (game.Workspace.Model.WheelBR.Size.Y/2)
    		local wheelHeight4 = game.Workspace.Model.WheelBL.Position.Y - position4.Y - (game.Workspace.Model.WheelBL.Size.Y/2)
    		local k = game.Workspace.Model.kConst.Value
    		local c = game.Workspace.Model.cConst.Value
    		
    		if hit1 then
    			local force1 = -k*(height1 - equi) - game.Workspace.Model.ThrustFR.Velocity.Y*c 
    			game.Workspace.Model.ThrustFR.VectorForce.Force = Vector3.new(0, force1, 0)
    		else
    			game.Workspace.Model.ThrustFR.VectorForce.Force = Vector3.new(0, 0, 0)
    		end
    		
    		if hit2 then
    			local force2 = -k*(height2 - equi) - game.Workspace.Model.ThrustFL.Velocity.Y*c
    			game.Workspace.Model.ThrustFL.VectorForce.Force = Vector3.new(0, force2, 0)
    		else
    			game.Workspace.Model.ThrustFL.VectorForce.Force = Vector3.new(0, 0, 0)
    		end
    		
    		if hit3 then
    			local force3 = -k*(height3 - equi) - game.Workspace.Model.ThrustBR.Velocity.Y*c
    			game.Workspace.Model.ThrustBR.VectorForce.Force = Vector3.new(0, force3, 0)
    		else
    			game.Workspace.Model.ThrustBR.VectorForce.Force = Vector3.new(0, 0, 0)
    		end
    		
    		if hit4 then
    			local force4 = -k*(height4 - equi) - game.Workspace.Model.ThrustBL.Velocity.Y*c 
    			game.Workspace.Model.ThrustBL.VectorForce.Force = Vector3.new(0, force4, 0)
    		else
    			game.Workspace.Model.ThrustBL.VectorForce.Force = Vector3.new(0, 0, 0)
    		end
    		
    		if math.abs(game.Workspace.Model.Car.Orientation.X) < 25 and math.abs(game.Workspace.Model.Car.Orientation.Z) < 25 then
    			local x, y, z, R00, R01, R02, R10, R11, R12, R20, R21, R22 = game.Workspace.Model.ThrustFR.wheelWeld.C0:GetComponents()
    			game.Workspace.Model.ThrustFR.wheelWeld.C0 = CFrame.new(game.Workspace.Model.ThrustFR.wheelWeld.C0.X, game.Workspace.Model.ThrustFR.wheelWeld.C0.Y - wheelHeight1, game.Workspace.Model.ThrustFR.wheelWeld.C0.Z, R00, R01, R02, R10, R11, R12, R20, R21, R22)
    		end
    		if math.abs(game.Workspace.Model.Car.Orientation.X) < 25 and math.abs(game.Workspace.Model.Car.Orientation.Z) < 25 then
    			local x, y, z, R002, R012, R022, R102, R112, R122, R202, R212, R222 = game.Workspace.Model.ThrustFL.wheelWeld.C0:GetComponents()
    			game.Workspace.Model.ThrustFL.wheelWeld.C0 = CFrame.new(game.Workspace.Model.ThrustFL.wheelWeld.C0.X, game.Workspace.Model.ThrustFL.wheelWeld.C0.Y - wheelHeight2, game.Workspace.Model.ThrustFL.wheelWeld.C0.Z, R002, R012, R022, R102, R112, R122, R202, R212, R222)
    		end
    		if math.abs(game.Workspace.Model.Car.Orientation.X) < 25 and math.abs(game.Workspace.Model.Car.Orientation.Z) < 25 then
    			local x, y, z, R003, R013, R023, R103, R113, R123, R203, R213, R223 = game.Workspace.Model.ThrustBR.wheelWeld.C0:GetComponents()
    			game.Workspace.Model.ThrustBR.wheelWeld.C0 = CFrame.new(game.Workspace.Model.ThrustBR.wheelWeld.C0.X, game.Workspace.Model.ThrustBR.wheelWeld.C0.Y - wheelHeight3, game.Workspace.Model.ThrustBR.wheelWeld.C0.Z, R003, R013, R023, R103, R113, R123, R203, R213, R223)
    		end
    		if math.abs(game.Workspace.Model.Car.Orientation.X) < 25 and math.abs(game.Workspace.Model.Car.Orientation.Z) < 25 then
    			local x, y, z, R004, R014, R024, R104, R114, R124, R204, R214, R224 = game.Workspace.Model.ThrustBL.wheelWeld.C0:GetComponents()
    			game.Workspace.Model.ThrustBL.wheelWeld.C0 = CFrame.new(game.Workspace.Model.ThrustBL.wheelWeld.C0.X, game.Workspace.Model.ThrustBL.wheelWeld.C0.Y - wheelHeight4, game.Workspace.Model.ThrustBL.wheelWeld.C0.Z, R004, R014, R024, R104, R114, R124, R204, R214, R224)
    		end
    	end)
    end)

When the car goes down a hill, it bounces around and doesn’t stay level. Does anyone have any idea why this is, as I think that the force terms are correct with damping included.

3 Likes

You should really use a for loop on this. You’re literally writing 4x the amount of code.

I’m away from my pc at the moment but I’ll look at this further when i get home.

Ah yes, thank you! I now have:

local Raycast = require(script.RaycastModule)
    spawn(function()
    	game:GetService("RunService").Stepped:connect(function()
    		local equi = 3
    		local k = game.Workspace.Model.kConst.Value
    		local c = game.Workspace.Model.cConst.Value

    		for i,v in pairs(game.Workspace.Model:GetChildren())do
    			if string.find(v.Name, "Thrust") then
    				local hit, position = Raycast.new(v.Position, v.CFrame:vectorToWorldSpace(Vector3.new(0, -1, 0)) * 3)
    				local height = v.Position.Y - position.Y
    				
    				if hit then
    					local force = -k*(height - equi) - c*v.Velocity.Y 
    					v.VectorForce.Force = Vector3.new(0, force, 0)
    				else
    					v.VectorForce.Force = Vector3.new(0, 0, 0)
    				end
    			end
    		end
    end)
    end)

And this is in a module script called RaycastModule:

local module = {}

function module.new(startPosition, startDirection)
	local maxDistance = startDirection.magnitude
	local direction = startDirection.unit
	local lastPosition = startPosition
	local distance = 0
	local ignore = {}
	
	local hit, position, normal
	
	repeat
		local ray = Ray.new(lastPosition, direction * (maxDistance - distance))
		hit, position, normal = game.Workspace:FindPartOnRayWithIgnoreList(ray, ignore, false, true)
		if hit then
			if not hit.CanCollide then
				table.insert(ignore, hit)
			end
		end
		distance = (startPosition - position).magnitude
		lastPosition = position
	until distance >= maxDistance - 0.1 or (hit and hit.CanCollide)
	return hit, position, normal
end

return module

Sorry about the messy code. It keeps indenting random lines.

Can you make a model that I can have so I may see what the issue is, without having to build a suspension system, and test it out using this script?