Raycast Vehicle Suspension Problem

Hello everyone. I’m working on a raycast vehicle suspension system, and there seems to be a problem which i have zero idea of how to solve. Basically, when there’s one vehicle inside of the game, it works perfectly fine. But when there’s multiple vehicles, the suspension starts going crazy. Any ideas as to why this could happen?

The server script:

local existingVehicles = {}
local vehTable = require(game.ReplicatedStorage.Vehicles)

local function addVehicle(veh)
	if not existingVehicles[veh] then
		table.insert(existingVehicles, veh)
		veh:WaitForChild("Base"):SetNetworkOwner(nil)
		existingVehicles[veh] = {}
		existingVehicles[veh].wheelPositions = vehTable[veh.Name].wheelPositions
		existingVehicles[veh].springLengths = vehTable[veh.Name].springLengths
		existingVehicles[veh].properties = vehTable[veh.Name].properties
		existingVehicles[veh].wheelSuspensionLengthMemory = vehTable[veh.Name].wheelSuspensionLengthMemory
	end
end

for _, object in workspace:GetChildren() do
	if object:HasTag("Vehicle") then
		addVehicle(object)
	end
end

while true do
	local delta = game["Run Service"].Heartbeat:Wait()
	for i, vehicle in ipairs(existingVehicles) do
		local carModel = existingVehicles[i]
		local car = carModel.PrimaryPart
		local carCFrame = car.CFrame
		local params = RaycastParams.new()
		params.FilterDescendantsInstances = {carModel}
		
		local wheelPositions = existingVehicles[vehicle].wheelPositions
		local properties = existingVehicles[vehicle].properties
		local stiffness = properties.stiffness
		local damper = properties.damper
		local springLenghts = existingVehicles[vehicle].springLengths
		local wheelSuspensionLengthMemory = existingVehicles[vehicle].wheelSuspensionLengthMemory
		local wheelRadius = properties.wheelRadius
		local suspensionMaxLength = properties.suspensionMaxLength
		
		
		for wheelName, pos in pairs(wheelPositions) do
			local rayOrigin = carCFrame:ToWorldSpace(CFrame.new(pos)).Position
			local rayDirection = -carCFrame.UpVector * (suspensionMaxLength + wheelRadius)
			local raycast = workspace:Raycast(rayOrigin, rayDirection , params)
			if raycast then
				print("Ray Success")
				local raycastDistance = (raycast.Position - rayOrigin).Magnitude
				
				
				local springLength = math.clamp(raycastDistance - wheelRadius, 0, suspensionMaxLength)
				local stiffnessForce = stiffness * (suspensionMaxLength - wheelSuspensionLengthMemory[wheelName])
				local damperForce = damper * ((wheelSuspensionLengthMemory[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(car:GetVelocityAtPosition(raycast.Position)))
				
				local Xforce = carCFrame.RightVector * -LocalVelocity.X * wheelRadius
				
				wheelSuspensionLengthMemory[wheelName] = springLength
				
				car:ApplyImpulseAtPosition(suspensionForceVec3 + Xforce, rayOrigin)
			else
				print("Ray Nil")
			end
		end
	end
end

one vehicle:

multiple vehicles:

1 Like

I think the issue is this line

existingVehicles[veh].wheelSuspensionLengthMemory = vehTable[veh.Name].wheelSuspensionLengthMemory

because this makes it so that all vehicles share the same wheelSuspensionLengthMemory table, since you are assigning it by reference. Then you write data to the table in the for loop, which makes cars impact each other in the next iteration.

You should clone any tables you write data to. I think it will be fine if you only read from them, but you should probably mark that explicitly by calling table.freeze.

Also some other issues

  • using existingVehicles to store vehicle instances and vehicle information is very confusing; you should split into two tables
  • carModel and vehicle reference the exact same instance in the for loop, so you dont need to make the carModel variable
  • springLenghts is mispelled
2 Likes

thanks a lot, this worked! also thank you for correcting the spelling mistake lol

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