Hey devs, I’ve been trying to make some raycast suspensions for my car controller recently and it all worked fine until I noticed something weird: when I added a VehicleSeat and made the player hop on it, the car just fell to the ground. Then, a few seconds after, it would plummet in the sky…
I did some testing and noticed the following behavior: on the CLIENT, the car seems to fall on the floor; on the SERVER, the car is “floating” mid-air, at exactly the maximum height for the suspensions, until at some random point it updates to the same position as the client.
It seems like since the server thinks the car is floating it applies no suspension force, meaning the one on the client stays on the ground; then, when it randomly updates to the correct position, since the distance between the suspensions and the ground is basically 0 the force becomes absurdly high and launches me in the air.
Does anybody have any idea why this desync is happening? Here’s a video and the code for my suspensions:
local RunService = game:GetService("RunService")
local CarModel = script.Parent
local Root = CarModel.CarRoot
local Wheels = Root.Wheels:GetChildren()
local Config = { -- I use a dynamic config table but this is basically what the code in my video example works with
Suspensions = {
Damper = 10000 -- 10k
Stiffness = 140000 -- 140k; this high since part denisty is set to 100
MaxExtension = 2 -- How far the suspensions can extend
RestLen = 2 -- The spring length at rest
WheelRadius = 1
MinLen = 0 -- RestLen - MaxExtension
MaxLen = 4 -- RestLen + Max Extension
}
}
for _, part in CarModel:GetDescendants() do
if part:IsA("BasePart") then
part:SetNetworkOwner(nil)
end
end
--// Suspensions
local lastSpringLen = {}
for _, Wheel:Attachment in Wheels do
lastSpringLen[Wheel.Name] = 0
local wheelForce = Instance.new("VectorForce", Root.Suspensions)
wheelForce.Visible = true
wheelForce.Attachment0 = Wheel
wheelForce.Force = Vector3.new(0,0,0)
wheelForce.Name = Wheel.Name
end
RunService.Stepped:Connect(function(_,dt)
local rcParams = RaycastParams.new()
rcParams.FilterDescendantsInstances = {CarModel}
if CarModel.Seats.Driver.Occupant then rcParams:AddToFilter(CarModel.Seats.Driver.Occupant.Parent) end
rcParams.FilterType = Enum.RaycastFilterType.Exclude
local lconfig = Config.Suspensions
for _, Wheel:Attachment in Wheels do
local SpringLen = lconfig.RestLen
local suspRay = workspace:Raycast(Wheel.WorldPosition,-Wheel.WorldSecondaryAxis*lconfig.MaxLen,rcParams)
if suspRay then
print("Ray length: "..suspRay.Distance)
Wheel.RayVis.Length = suspRay.Distance
SpringLen = math.clamp(suspRay.Distance - lconfig.WheelRadius,lconfig.MinLen,lconfig.MaxLen)
else
Wheel.RayVis.Length = lconfig.MaxLen
print("Ray hit nothing")
end
local SpringForce = lconfig.Stiffness * (lconfig.RestLen - SpringLen)
local DampForce = lconfig.Damper * (lastSpringLen[Wheel.Name] - SpringLen) / dt
Root.Suspensions[Wheel.Name].Force = Vector3.new(0,SpringForce + DampForce,0)
lastSpringLen[Wheel.Name] = SpringLen
end
end)
Anything helps!