Car bounces up and down rather than remaining level (VectorForces)

I have a car with only suspension which is handled by a script and VectorForce and it should be level and not move at all except when it goes over a bump.

The problem is that the car bounces around and it appears that the force generated gradually grows over time until it goes too high and the force is set back to 0 and falls back down where it repeats.
https://gyazo.com/fec6efc04e7aa4754f6ae48ffdacfc9e

Script:

-- // Services
local ReplicatedStorage, RunService = game:GetService("ReplicatedStorage"), game:GetService("RunService")

-- // Variables
local Car = script.Parent
local Wheels = {}

local MaxSuspensionLength = 4
local MaxSuspensionForce = 10000
local DampeningRatio = 0.99

local SuspensionLoopConnection = nil

-- // Functions
local function CreateWeld(Part0: BasePart, Part1: BasePart, Parent: Instance?)
	local Weld = Instance.new("Weld")
	Weld.Part0 = Part0
	Weld.Part1 = Part1

	Weld.Parent = Parent or Part0
end

local function CreateWheel(Attachment: Attachment): Part
	local NewWheel = ReplicatedStorage:FindFirstChild("TemplateWheel"):Clone()
	NewWheel.Parent = Car
	NewWheel.Position = Attachment.WorldCFrame.Position
	
	local VectorForce = Instance.new("VectorForce")
	VectorForce.Parent = NewWheel
	VectorForce.Attachment0 = Attachment
	VectorForce.RelativeTo = Enum.ActuatorRelativeTo.World
	
	return NewWheel
end

local function UpdateSuspension()
	-- Loop trough all wheels
	for index, wheel in pairs(Wheels) do
		
		-- Get VectorForce object
		local VectorForce: VectorForce = wheel["Wheel"].VectorForce
		
		if not VectorForce.Attachment0 then return end
		
		-- Get attachment
		local Attachment: Attachment = VectorForce.Attachment0
		
		-- Raycast
		local Direction = -Attachment.WorldCFrame.UpVector * MaxSuspensionLength
		local RayResult = workspace:Raycast(Attachment.WorldCFrame.Position, Direction)
		
		-- If raycast found the thingymabob
		if RayResult then
			local RayInstance, DistanceToGround = RayResult.Instance, RayResult.Distance
			
			-- If raycast instance is the baseplate (ground)
			if RayInstance == workspace.Baseplate then
				
				local SuspensionCompressionRatio = 1 - (DistanceToGround / MaxSuspensionLength)
				local DesiredForce = SuspensionCompressionRatio * MaxSuspensionForce
				local Force = DesiredForce + (wheel["LastForce"] - DesiredForce) * DampeningRatio
				
				-- Make wheels stick to ground
				wheel["Wheel"].Weld.C0 = Attachment.CFrame * CFrame.new(0, -DistanceToGround + wheel["Wheel"].Size.Y * 0.5, 0)
				
				-- Apply force to wheel
				VectorForce.Force = Vector3.new(0, Force, 0)
				
				wheel["LastForce"] = Force

			end

		else
			VectorForce.Force = Vector3.new(0, 0, 0)
			--wheel["LastForce"] = 0
		end

	end
end

local function SetupCar()
	for _, attachment: Attachment in pairs(Car.Chassis:GetChildren()) do
		if attachment.Name == "WheelAttachment" then

			local Wheel = CreateWheel(attachment)
			Wheels[Wheel] = {Wheel = Wheel, LastForce = 0.5}

			CreateWeld(Car.Chassis, Wheel, Wheel)

		end
	end
end

-- // Setup
SetupCar()


-- // Connections
SuspensionLoopConnection = RunService.Heartbeat:Connect(UpdateSuspension)

If you think you may have a solution or suggestion, please reply!

Hello, It is pretty hard to help you from here and understand everything but I believe that the problem might be stemming from the way you are updating your suspension force. Your UpdateSuspension() function seems to be continuously updating the VectorForce of each wheel, which could be leading to a growing force over time and causing the bouncing effect.

Maybe try this:

  1. Ensure proper damping: It appears that you’re using a damping factor (DampeningRatio), but the way it’s applied may be incorrect. In your code, you’re essentially applying the damping to the difference between the desired force and the last force. However, damping is typically applied to the velocity or speed of change, not to the difference in forces. You might want to revise how you’re applying your damping factor.

  2. Add a spring constant: Generally, suspension systems are modelled using spring-damper systems, where there is a spring constant k that determines how stiff the spring is, and a damping constant b that determines how much the spring’s movement is damped. In your code, you are directly assigning a force to the suspension based on the compression ratio, without taking into account a spring constant. This could potentially lead to unrealistic behavior.

  3. Use correct raycast direction: You have used MaxSuspensionLength for the direction of the raycast, which seems incorrect. Raycast direction should be normalized (have a magnitude of 1), and the length of the raycast should be controlled separately.

  4. Adjust maximum suspension force: The MaxSuspensionForce might be set too high, causing too much bounce. Try tuning down this value and see if it stabilizes your car.

Hope It helps in any way!

1 Like