So i have a raycast car script that works fine on 60Fps but when the client runs at 30fps or lower the car starts to wobble.
im not sure how to fix it i have looked at other devforum post about this topic but it didnt help.
60Fps:
30Fps:
The code is from a tutorial i followed i just changed it from ApplyImpulse to VectorForces.
Here is the code:
for wheelName,pos in pairs(props.WheelPositions)do
local Att = Instance.new("Attachment")
Att.Parent = carPrim
Att.WorldPosition = carPrim.CFrame:ToWorldSpace(CFrame.new(pos)).p
print(Att)
local vectorForce = Instance.new("VectorForce", Att)
vectorForce.Force = Vector3.new(0,0,0)
vectorForce.Attachment0 = Att
vectorForce.RelativeTo = Enum.ActuatorRelativeTo.World
VectorForces[wheelName] = {}
VectorForces[wheelName].attachment = Att
VectorForces[wheelName].vector = vectorForce
SpringLengthMemory[wheelName] = 0.5
end
while true do
local delta = game["Run Service"].Heartbeat:Wait()
local carPrim = carModel.PrimaryPart
SmoothSteer = math.abs(
seatPart.SteerFloat-SmoothSteer)<=delta*5 and seatPart.SteerFloat or SmoothSteer+math.sign(
seatPart.SteerFloat-SmoothSteer)*delta*5
for wheelName, originalPosition in pairs(props.WheelPositions)do
local Att = VectorForces[wheelName].attachment
local wheelVF = VectorForces[wheelName].vector
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
Att.WorldPosition = raycast.Position
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 YSuspensionForce = Vector3.new(0,SuspensionForceVec3.Y,0)
local RotationsOnlyWheelDirCFrame = CFrame.lookAt(Vector3.zero,carCFrame.LookVector,carCFrame.UpVector)
if string.sub(wheelName,1,1)=='F' then
RotationsOnlyWheelDirCFrame = RotationsOnlyWheelDirCFrame * CFrame.Angles(0,-math.rad(SmoothSteer * props.SteerAngle),0)
end
local LocalVelocity = RotationsOnlyWheelDirCFrame:ToObjectSpace(CFrame.new(carPrim:GetVelocityAtPosition(raycast.Position)))
local Xforce = RotationsOnlyWheelDirCFrame.RightVector * -LocalVelocity.x * props.wheelFriction
local fuel = carModel:GetAttribute("fuel")
local throttleForce = 0
if fuel and fuel > 0 and not carModel.Destroyed.Value then
-- Only apply throttle force if fuel is available
throttleForce = seatPart.ThrottleFloat * carModel:GetAttribute("torque") * (
(math.sign(-LocalVelocity.z) == seatPart.Throttle and (1 - math.min(1, math.abs(LocalVelocity.z) / carModel:GetAttribute("maxSpeed")))) or 1
)
end
local Zforce = RotationsOnlyWheelDirCFrame.LookVector * throttleForce
SpringLengthMemory[wheelName] = SpringLength
wheelVF.Force = (SuspensionForceVec3 + Xforce + Zforce) * 60
--carPrim:ApplyImpulseAtPosition((SuspensionForceVec3 + Xforce + Zforce) * delta * 60, raycast.Position)
else
wheelVF.Force = Vector3.new(0,0,0)
SpringLengthMemory[wheelName] = props.SuspensionMaxLength
end
if VisualiseRaycast then PlrGui.gaag.ag.CurrentCamera = workspace.CurrentCamera PlrGui.gaag.ag2.CurrentCamera = workspace.CurrentCamera coroutine.wrap(function()local p = Instance.new("Part",PlrGui.gaag.ag)p.Name = 'rayVis'p.Color = Color3.new(0,0,1)p.Anchored = true p.CanCollide = false p.CollisionGroupId = 1 p.Material = Enum.Material.Neon p.Shape = Enum.PartType.Cylinder local pe = p:Clone()pe.Color = Color3.new(1,0,0)pe.Parent = p.Parent local Rdestination = (rayOrigin + rayDirection)if raycast then local rDist = (rayOrigin - raycast.Position).magnitude local s = rayOrigin - carCFrame.UpVector * rDist/2 p.CFrame = CFrame.lookAt(s, s + carCFrame.RightVector,-carCFrame.LookVector) p.Size = Vector3.new(rDist, 0.1, 0.1)rDist = (raycast.Position - Rdestination).magnitude s = raycast.Position - carCFrame.UpVector * rDist/2 pe.Size = Vector3.new(rDist, 0.1, 0.1)pe.CFrame = CFrame.lookAt(s, s + carCFrame.RightVector,-carCFrame.LookVector)else p.Size = Vector3.new((rayOrigin - Rdestination).magnitude, 0.1, 0.1)local s = rayOrigin + rayDirection/2 p.CFrame = CFrame.lookAt(s, s + carCFrame.RightVector,-carCFrame.LookVector)Rdestination = Rdestination + carCFrame.UpVector*0.02 pe.CFrame = CFrame.lookAt(Rdestination, Rdestination + carCFrame.RightVector,-carCFrame.LookVector)pe.Size = Vector3.new(0,0.1,0.1)end local pp = p:Clone()pp.Parent = PlrGui.gaag.ag2 pp.Size = p.Size + Vector3.new(0.01,0.01,0.01)local ppe = pe:Clone() ppe.Parent = pp.Parent ppe.Size = pe.Size + Vector3.new(0.01,0.01,0.01)game["Run Service"].Heartbeat:Wait()pp:Destroy()ppe:Destroy()p:Destroy()pe:Destroy()end)()end
end``` The *60 at the end of Force is for the Mass i think because when i didnt have it * 60 it didnt have enough force to push it self of the ground. The model itself is massless and the chassis consist of one part which has mass of 62.