Raycasting Suspension Scripting Help

Hi All,

I am trying to make a raycasting suspension system for a car.

After seeing this video, I decided to give raycast suspension a try because it suits my needs - Space Dust Racing UE4 Arcade Vehicle Physics Tour - YouTube

In my initial attempt at creating the raycast suspension, the “vehicle” (currently just a part) does float but it rocks (tilts & slides) back and forth.

After some further searching, I found this link where Oseday shares his suspension mathematics - Car Suspension (Scripted) - #5 by Kampfkarren

Unfortunately, I don’t really understand the math. I tried my best to implement it, but it still doesn’t balance and bounces up and down.

All assistance is appreciated, thanks in advance.

local d = 1 -- Suspension length?
local a = 1.8 --Stiffness, higher means higher height at suspension
local b = 0.6 --Rigidity higher means the suspensions will get less effected by slight changes and will balance out unlike Roblox's suspensions. This is the part that dampens the suspension.

local RunService = game:GetService("RunService")

local ST = {dx=0,d2x=0} --For storing the derivatives per suspension

local body = script.Parent

-- Initialise suspension force

local backLeftBodyThrust = Instance.new("BodyThrust")
backLeftBodyThrust.Name = "BackLeftBodyThrust"
backLeftBodyThrust.Location = Vector3.new(body.size.X/2, body.size.Y/2, body.size.Z/2)
backLeftBodyThrust.Parent = body

local backRightBodyThrust = Instance.new("BodyThrust")
backRightBodyThrust.Name = "BackRightBodyThrust"
backRightBodyThrust.Location = Vector3.new(-body.size.X/2, body.size.Y/2, body.size.Z/2)
backRightBodyThrust.Parent = body

local frontLeftBodyThrust = Instance.new("BodyThrust")
frontLeftBodyThrust.Name = "FrontLeftBodyThrust"
frontLeftBodyThrust.Location = Vector3.new(body.size.X/2, body.size.Y/2, -body.size.Z/2)
frontLeftBodyThrust.Parent = body

local frontRightBodyThrust = Instance.new("BodyThrust")
frontRightBodyThrust.Name = "FrontRightBodyThrust"
frontRightBodyThrust.Location = Vector3.new(-body.size.X/2, body.size.Y/2, -body.size.Z/2)
frontRightBodyThrust.Parent = body

RunService.Heartbeat:Connect(function()
	
	local corners = {
		backLeftCorner = body.Position - Vector3.new(body.size.X/2, 0, body.size.Z/2),
		backRightCorner = body.Position - Vector3.new(-body.size.X/2, 0, body.size.Z/2),
		frontLeftCorner = body.Position - Vector3.new(body.size.X/2, 0, -body.size.Z/2),
		frontRightCorner = body.Position - Vector3.new(-body.size.X/2, 0, -body.size.Z/2),
	}
	
	local forces = {
		
	}
	
	for i, corner in pairs(corners) do
		
		local rayOrigin = corner
		local rayDirection = Vector3.new(0,-100,0)

		local raycastParams = RaycastParams.new()
		raycastParams.FilterDescendantsInstances = {body}
		raycastParams.FilterType = Enum.RaycastFilterType.Blacklist
		local raycastResult = workspace:Raycast(rayOrigin, rayDirection, raycastParams)
		
		local x
		
		if raycastResult then
		        x = d-(corner - raycastResult.Position).Magnitude

			local f = (a*x + b*(x-ST.dx) + b/2*(x-ST.d2x)) * body.Mass/2 --Use the equation

			ST.d2x = ST.dx --Store the past values
			ST.dx = x
			
			table.insert(forces, Vector3.new(0,f,0))
			--Wheel.Force = Vector3.new(0,-f,0)
		end
	end
	print(forces)
	
	backLeftBodyThrust.Force = forces[1]
	backRightBodyThrust.Force = forces[2]
	frontLeftBodyThrust.Force = forces[3]
	frontRightBodyThrust.Force = forces[4]
end)
4 Likes

Hi Everyone,

Just as a little bit of an update, I have tried a slightly different equation however still experiencing the same issues. All assistance is appreciated.

local suspensionLength = 10
local stiffness = 6

local RunService = game:GetService("RunService")

local body = script.Parent

local suspensionDamping = 2*math.sqrt(stiffness)


-- Initialise suspension force

local backLeftBodyThrust = Instance.new("BodyThrust")
backLeftBodyThrust.Name = "BackLeftBodyThrust"
backLeftBodyThrust.Location = Vector3.new(body.size.X/2, body.size.Y/2, body.size.Z/2)
backLeftBodyThrust.Parent = body

local backRightBodyThrust = Instance.new("BodyThrust")
backRightBodyThrust.Name = "BackRightBodyThrust"
backRightBodyThrust.Location = Vector3.new(-body.size.X/2, body.size.Y/2, body.size.Z/2)
backRightBodyThrust.Parent = body

local frontLeftBodyThrust = Instance.new("BodyThrust")
frontLeftBodyThrust.Name = "FrontLeftBodyThrust"
frontLeftBodyThrust.Location = Vector3.new(body.size.X/2, body.size.Y/2, -body.size.Z/2)
frontLeftBodyThrust.Parent = body

local frontRightBodyThrust = Instance.new("BodyThrust")
frontRightBodyThrust.Name = "FrontRightBodyThrust"
frontRightBodyThrust.Location = Vector3.new(-body.size.X/2, body.size.Y/2, -body.size.Z/2)
frontRightBodyThrust.Parent = body

local previousMagnitude = {0}

RunService.Heartbeat:Connect(function(delta)
	
	-- calculate position of corners
	
	local corners = {
		backLeftCorner = body.Position - Vector3.new(body.size.X/2, 0, body.size.Z/2),
		backRightCorner = body.Position - Vector3.new(-body.size.X/2, 0, body.size.Z/2),
		frontLeftCorner = body.Position - Vector3.new(body.size.X/2, 0, -body.size.Z/2),
		frontRightCorner = body.Position - Vector3.new(-body.size.X/2, 0, -body.size.Z/2),
	}
	
	local magnitude = {}
	
	-- Create raycast originating from each corner

	for i, corner in pairs(corners) do
	
		local rayOrigin = corner
		local rayDirection = Vector3.new(0,-100,0)
		
		local raycastParams = RaycastParams.new()
		raycastParams.FilterDescendantsInstances = {body}
		raycastParams.FilterType = Enum.RaycastFilterType.Blacklist
		local raycastResult = workspace:Raycast(rayOrigin, rayDirection, raycastParams)
		
		-- if result send length return length of ray
		
		if raycastResult then
			if (corner - raycastResult.Position).Magnitude <= suspensionLength then
				table.insert(magnitude, (corner - raycastResult.Position).Magnitude)
			else
				table.insert(magnitude, suspensionLength)
			end
		end
	end
	
	if magnitude[1] then	
		
		if previousMagnitude[1] ~= 0 then
			backLeftBodyThrust.Force = Vector3.new(0, (-(magnitude[1] - suspensionLength)*stiffness-(suspensionDamping*(magnitude[1]-previousMagnitude[1])/delta))*body.Mass, 0)
			backRightBodyThrust.Force = Vector3.new(0, (-(magnitude[2] - suspensionLength)*stiffness-(suspensionDamping*(magnitude[2]-previousMagnitude[2])/delta))*body.Mass, 0)
			frontLeftBodyThrust.Force = Vector3.new(0, (-(magnitude[3] - suspensionLength)*stiffness-(suspensionDamping*(magnitude[3]-previousMagnitude[3])/delta))*body.Mass, 0)
			frontRightBodyThrust.Force = Vector3.new(0, (-(magnitude[4] - suspensionLength)*stiffness-(suspensionDamping*(magnitude[4]-previousMagnitude[4])/delta))*body.Mass, 0)
		end
		
		previousMagnitude = magnitude
		
	end
	
	return(magnitude)
end)
2 Likes

CarSuspension2.rbxm (7.2 KB)

As a bit of an update I have attached my latest attempt as a roblox model.

I have multiplied the mass by gravity and divided by 4 (the number of thrusters). However, now it’s just bouncing up and down chaotically.

2 Likes

This raycasts suspension might help : https://www.youtube.com/watch?v=WSxGsKypFCw&t=452s

1 Like