Help with Car Suspension/ApplyImpulseAtPosition

I have a very specific problem and I am looking for help finding a workaround, up until now I have been using a car suspension system based on spring constraints, which while functional was sub optimal.

After researching I was able to find a solid chunk of code to use for my Vehicles but it has a few issues,

Properties Module:

local module = {

	Wingman = {
		SuspensionMaxLength = 2.8,
		wheelRadius = 1.5,

		Stiffness = 120,
		Damper = 6,

		wheelFriction = 5.5,
		torque = 30,
		MaxSpeed = 90,
		SteerAngle = 30,

		WheelPositions = {
			FLwheel = Vector3.new(3.424, 0, 6.117),
			FRwheel = Vector3.new(-3.438, 0, 6.117),
			RLwheel = Vector3.new(3.423, 0, -5.767),
			RRwheel = Vector3.new(-3.438, 0, -5.75),
		},
	},

	--here its possible to copy table above and make more cars just this simply

}
return module

Main Code:

local CarPrim = Seat.Parent.PrimaryPart
local CarModel = Seat.Parent
local SpringLengthMemory = {}
for i,v in pairs(props.WheelPositions)do SpringLengthMemory[i] = 0.5 end
coroutine.wrap(function()
	while Connnection ~= Seat do
		local delta = game["Run Service"].Heartbeat:Wait()
		for wheelName, originalPosition in pairs(props.WheelPositions)do
			local carCFrame = CarPrim.CFrame
			local rayOrigin = carCFrame:ToWorldSpace(CFrame.new(originalPosition)).p
			local rayDirection = -carCFrame.UpVector * (props.SuspensionMaxLength + props.wheelRadius)
			local rayParams = RaycastParams.new()
			rayParams.FilterDescendantsInstances = {CarModel}

			local raycast = workspace:Raycast(rayOrigin,rayDirection,rayParams)
			if raycast then


				local RaycastDistance = (rayOrigin - raycast.Position).magnitude

				local SpringLength = math.clamp(RaycastDistance - props.wheelRadius, 0, props.SuspensionMaxLength)
				local StiffnessForce = props.Stiffness * (props.SuspensionMaxLength - SpringLength)
				local DamperForce = props.Damper * (( SpringLengthMemory[wheelName] - SpringLength) / delta)
				local SuspensionForceVec3 = carCFrame.UpVector * (StiffnessForce + DamperForce)

				local RotationsOnlyWheelDirCFrame = CFrame.lookAt(Vector3.zero,carCFrame.LookVector,carCFrame.UpVector)
				local LocalVelocity = RotationsOnlyWheelDirCFrame:ToObjectSpace(CFrame.new(CarPrim:GetVelocityAtPosition(raycast.Position)))

				local Xforce = RotationsOnlyWheelDirCFrame.RightVector * -LocalVelocity.x * props.wheelFriction
				local Zforce = RotationsOnlyWheelDirCFrame.LookVector * Seat.ThrottleFloat * props.torque * (math.sign(-LocalVelocity.z)==Seat.Throttle and(1 - math.min(1,math.abs(LocalVelocity.z)/props.MaxSpeed))or 1)

				SpringLengthMemory[wheelName] = SpringLength

				CarPrim:ApplyImpulseAtPosition(SuspensionForceVec3 + Xforce + Zforce, raycast.Position)

			else
				SpringLengthMemory[wheelName] = props.SuspensionMaxLength
			end
		end
		wait()
	end
end) ()

(Video I sourced the Code from)

The person who was initially using this code had a custom system for the wheels, the wheels were not physics based and instead simply welded to the car, with him applying velocity to the car itself for movement instead of the wheels.

I however have a physics based system using CylindricalConstraints as the motors for the wheels:
Screenshot 2024-05-16 114354

And that’s where the problem is, :ApplyImpulseAtPosition() doesn’t work for my car’s wheels (at least not in the way this code handles it), When I try to run it the car just starts bouncing all over the place and doesn’t appreciate life very much.

If anyone can help think of a way to modify the code into working, while also keeping the wheels the way they are I would appreciate that greatly.

1 Like

I was able to fix this problem later on my own, However I’m still having other issues and I’m probably going to end up needing to make more posts.

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.