[*Solved*]Problem With Raycasting Car In Low FPS

  1. **What do you want to achieve?
    a stable chassis.

  2. **What is the issue?
    the chassis shakes and jumps uncontrollably when the player has low fps.

  3. **What solutions have you tried so far?
    changing “RenderStepped” for “while true do”(dont worked), changing script to server(dont worked).

This chassis is not mine, I acquired it for free from a YouTube video: https://www.youtube.com/watch?v=8nhBraNqlek

Lag testing video: https://www.youtube.com/watch?v=k9UzDeChNyM

Model Link: https://create.roblox.com/store/asset/14909663751/RaycastCarV104?viewFromStudio=true&keyword=&searchId=16209d4c-5859-4ae6-9983-0b9424a98436

Raycasting Script:

local rep = game:GetService(“ReplicatedStorage”)
local runservice = game:GetService(“RunService”)
local tweenService = game:GetService(“TweenService”)
local userinputservice = game:GetService(“UserInputService”)

local player = game.Players.LocalPlayer
local plrgui = player.PlayerGui

local carfunc
local carfunc2
local carfunc3
local seatPart
local previousSeat

local steeringangle = 0
local steeringspeed = 0
local steeringdecay = 0.97
local steeringaccel = 0.08
local steeringSpeedDecay = 0.00006
local steeringmaxspeed = 30
local steeringmaxangle = 450

local character = script.Parent

–local lastspringdist = {}

local keybinds = {
LeftShift = 0,
LeftControl = 0,
W = 0,
S = 0,
A = 0,
D = 0,
E = 0,
Q = 0
}

local function handleInput(key, isKeyDown)
for i,v in pairs(keybinds) do
if key.KeyCode == Enum.KeyCode[i] then
keybinds[i] = isKeyDown
end
end
end

local function frictionCurve(x)
return math.clamp(20/(x+0.3) , 0.5, 10)
end

local function speedFormula(m1, v1, m2, v2) --inelastic collision formula
return (m1v1 + m2v2)/(m1+m2)
end

local function powerCurve(rpm, power, peak)
return power * (-0.0015 * (rpm-peak)^2 + 4)
end

local function customLerp(value1, value2, factor)
return value1 + (value2 - value1) * factor
end

character.Humanoid:GetPropertyChangedSignal(“SeatPart”):Connect(function()
seatPart = character.Humanoid.SeatPart

if seatPart == nil then
	if carfunc then
		carfunc:Disconnect()
		carfunc2:Disconnect()
		carfunc3:Disconnect()
		for _,v in pairs(previousSeat.Parent:GetDescendants()) do
			if v:IsA("VectorForce") then
				v.Force = Vector3.new(0,0,0)
			elseif v:IsA("Sound") then
				v.Playing = false
			end
		end
	else
		warn("carfunc is nil. not an issue if player wasnt on vehicleseat")
	end
	print("end")
	return
else
	previousSeat = seatPart
end

if not seatPart:IsA("VehicleSeat") then
	return
end


local car = seatPart.Parent
local physics = car.Physics
local wheels = car.Wheels
local tune = car.Tune

for _,v in pairs(seatPart.Parent:GetDescendants()) do
	if v:IsA("Sound") then
		v.Playing = true
	end
end

-----------------------------------------------------------------------------------------DEBUG
local debugModels = {
	physics,
	car.Mass,
}

local meshModels = {
	--car.BodyMesh,

}

local function setDebugTransparency(meshTrans, debugTrans)
	for _,wheel in pairs(car.Wheels:GetChildren()) do
		wheel.Mesh.Transparency = debugTrans
		wheel.AppearanceWheel.Transparency = debugTrans
		wheel.AppearanceWheel.WheelMesh.Transparency = meshTrans
		wheel.AppearanceWheel.WheelMesh.Blur.Transparency = meshTrans
	end

	for _,mesh in pairs(debugModels) do
		mesh.Transparency = debugTrans
	end

	for _,mesh in pairs(meshModels) do
		mesh.Transparency = meshTrans
	end
end

local function toggleModelDebug()
	if physics.Transparency == 1 then
		setDebugTransparency(1, 0.3)
	else
		setDebugTransparency(0, 1)
	end
end
-----------------------------------------------------------------------------------------

-----------------------------------------------------------------------------------------DRIVETRAIN
local drivenWheels
local numdrivenWheels

local drivetrain = tune.Drivetrain.Value

if drivetrain == "RWD" then
	drivenWheels = {"RL", "RR"}
	numdrivenWheels = 2
elseif drivetrain == "FWD" then
	drivenWheels = {"FL", "FR"}
	numdrivenWheels = 2
elseif drivetrain == "AWD" then
	drivenWheels = {"FL", "FR", "RL", "RR"}
	numdrivenWheels = 4
else
	return
end
-----------------------------------------------------------------------------------------

-----------------------------------------------------------------------------------------RANDOMJUNK
local clutch = seatPart.Clutch
local maxClutch = 1

local engineSpeed = 0
local frontwheelSpeed = 0
local rearwheelSpeed = 0
local engineMass = 10
local wheelMass = 3

local engineThrottle = seatPart.CustomThrottle
local braking = seatPart.CustomBrake
local pbrake = 1
local brakeForce = 0.75

local paleovelocity
local neovelocity
-----------------------------------------------------------------------------------------

-----------------------------------------------------------------------------------------SOUND
local sounds = car.Sounds
local skid = sounds.Skid
local road = sounds.Road
local idle = sounds.Idle
local rev = sounds.Rev

local soundslip = 0
-----------------------------------------------------------------------------------------

-----------------------------------------------------------------------------------------TRANSMISSION
local transTable = {
	[1] = 0.7,
	[2] = 1.3,
	[3] = 1.6,
	[4] = 1.95,
	[5] = 2.1,
}

local reverseRatio = -1

local gearSelection = 1
local gearRatio = transTable[1]
local neutral = 1 --1 means gear is not in neutral

local function gearShift(factor)
	if clutch.Value < maxClutch then
		gearSelection = math.clamp(gearSelection + factor, -1, 5)
		if gearSelection > 0 then
			neutral = 1
			gearRatio = transTable[gearSelection]

		elseif gearSelection < 0 then
			neutral = 1
			gearRatio = reverseRatio

		elseif gearSelection == 0 then
			neutral = 0
		end

		plrgui.ScreenGui.Gear.Value.Text = gearSelection
	end
end
-----------------------------------------------------------------------------------------
carfunc = runservice.RenderStepped:Connect(function(deltaTime)
	local deltaMulti = deltaTime*60

	local frontspringlength = tune.FrontSpringLength.Value
	local rearspringlength = tune.RearSpringLength.Value
	local springstrength = tune.SpringStrength.Value
	local damperstrength = tune.DamperStrength.Value
	local friction = tune.Friction.Value
	local power = tune.Power.Value
	local averagefrontfriction = seatPart.AverageFrontFriction
	local averagerearfriction = seatPart.AverageRearFriction
	local peakPWR = tune.PeakPower.Value
	local maxRPM = tune.MaxRPM.Value
	local springlowerlimit = tune.SpringLowerLimit.Value

	-----------------------------------------------------------------------------------------SPEED
	local carSpeed = physics.CFrame:vectorToObjectSpace(physics.Velocity)
	local carSpeedFront = carSpeed.Z

	-----------------------------------------------------------------------------------------BRAKES
	local brakeMulti

	local idleRPM = 10 --mutliply my 100 for real rpm
	if braking.Value == brakeForce then
		brakeMulti = braking.Value - math.max((0.2/(math.abs(0.05 * carSpeedFront) + 1) - (engineThrottle.Value * 0.2)), 0)
	else
		brakeMulti = braking.Value
	end
	-----------------------------------------------------------------------------------------ENGINE

	engineSpeed = math.clamp(engineSpeed + powerCurve(engineSpeed/10, (power / numdrivenWheels)*deltaMulti * engineThrottle.Value, peakPWR), 0, maxRPM) - ((0.01 * (engineSpeed - idleRPM))*deltaMulti) --rev up minus engine brake
	frontwheelSpeed = customLerp(frontwheelSpeed, -carSpeedFront, math.clamp(averagefrontfriction.Value * 0.8 * deltaMulti, 0, 1)) * brakeMulti
	rearwheelSpeed = customLerp(rearwheelSpeed, -carSpeedFront, math.clamp(averagerearfriction.Value * 0.8 * deltaMulti, 0, 1)) * (brakeMulti + ((1-brakeMulti) * 0.3)) * pbrake

	local frontresultVelocity = speedFormula(engineMass/(math.abs((math.abs(gearRatio) + (1 - transTable[1])) ^ 4)), engineSpeed*gearRatio, wheelMass, frontwheelSpeed)
	local rearresultVelocity = speedFormula(engineMass/(math.abs((math.abs(gearRatio) + (1 - transTable[1])) ^ 4)), engineSpeed*gearRatio, wheelMass, rearwheelSpeed)

	local autoClutch = math.clamp(0.1 * (engineSpeed - (idleRPM + 7)), 0, maxClutch) * clutch.Value

	if drivetrain == "RWD" then
		engineSpeed = customLerp(engineSpeed, rearresultVelocity/gearRatio, autoClutch * neutral)
		rearwheelSpeed = customLerp(rearwheelSpeed, rearresultVelocity, autoClutch * neutral)

	elseif drivetrain == "FWD" then
		engineSpeed = customLerp(engineSpeed, frontresultVelocity/gearRatio, autoClutch * neutral)
		frontwheelSpeed = customLerp(frontwheelSpeed, frontresultVelocity, autoClutch * neutral)

	elseif drivetrain == "AWD" then
		engineSpeed = customLerp(engineSpeed, frontresultVelocity/gearRatio, autoClutch * neutral)
		engineSpeed = customLerp(engineSpeed, rearresultVelocity/gearRatio, autoClutch * neutral)
		frontwheelSpeed = customLerp(frontwheelSpeed, frontresultVelocity, autoClutch * neutral)
		rearwheelSpeed = customLerp(rearwheelSpeed, rearresultVelocity, autoClutch * neutral)

	end

	-----------------------------------------------------------------------------------------SOUNDS
	idle.Volume = math.clamp((1 - engineThrottle.Value) * 0.5, 0, 5)
	idle.PlaybackSpeed = math.clamp(1 + ((1/maxRPM) * engineSpeed + (engineThrottle.Value * 0.2)), 0, 3)

	rev.Volume = math.clamp(((2/maxRPM) * engineSpeed + (engineThrottle.Value * 1)) * 0.5, 0, 5)
	rev.PlaybackSpeed = math.clamp(-0.3 + ((2/maxRPM) * engineSpeed + (engineThrottle.Value * 0.2)), 0 ,3)

	road.Volume = math.clamp(math.sqrt(physics.Velocity.Magnitude), 0, 2)
	road.PlaybackSpeed = math.clamp(0.3 + (physics.Velocity.Magnitude / 100), 0, 3)

	skid.Volume = math.clamp((soundslip - 0.2) * 0.1, 0 ,5)
	skid.PlaybackSpeed = math.clamp(soundslip * 0.05, 0, 1)

	soundslip = 0
	-----------------------------------------------------------------------------------------

	-----------------------------------------------------------------------------------------GUI
	plrgui.ScreenGui.EngineSpeed.Value.Text = math.floor(engineSpeed)
	plrgui.ScreenGui.RearWheelSpeed.Value.Text = math.floor(rearwheelSpeed)
	plrgui.ScreenGui.FrontWheelSpeed.Value.Text = math.floor(frontwheelSpeed)
	--plrgui.ScreenGui.ResultSpeed.Value.Text = math.floor(resultVelocity)

	plrgui.ScreenGui.EngineSpeed.Frame.Rotation = engineSpeed * 2
	plrgui.ScreenGui.RearWheelSpeed.Frame.Rotation = rearwheelSpeed
	plrgui.ScreenGui.FrontWheelSpeed.Frame.Rotation = frontwheelSpeed
	--plrgui.ScreenGui.ResultSpeed.Frame.Rotation = resultVelocity

	plrgui.ScreenGui.Gas.Size = UDim2.new(0, 10, engineThrottle.Value * 0.2, 0)
	plrgui.ScreenGui.Brake.Size = UDim2.new(0, 10, ((brakeForce/braking.Value) - brakeForce), 0)
	plrgui.ScreenGui.Clutch.Size = UDim2.new(0, 10, ((maxClutch - autoClutch)/maxClutch) * 0.2, 0)

	averagerearfriction.Value = 0
	averagefrontfriction.Value = 0
	-----------------------------------------------------------------------------------------

	-----------------------------------------------------------------------------------------G-FORCE
	neovelocity = carSpeed.Magnitude

	local acceleration
	if paleovelocity then
		acceleration = math.abs(neovelocity-paleovelocity) / deltaTime

		local gforce = acceleration*0.2

		plrgui.ScreenGui.GForce.Value.Text = math.floor(gforce)/10
		plrgui.ScreenGui.GForce.Frame.Rotation = gforce
	end
	-----------------------------------------------------------------------------------------
	-----------------------------------------------------------------------------------------AIR RESISTANCE
	car.Mass.AirResistance.AirForce.Force = physics.Velocity * -35
	-----------------------------------------------------------------------------------------

	-----------------------------------------------------------------------------------------WHEELS
	for _,attachment in pairs(physics:GetChildren()) do
		local wheel = wheels:FindFirstChild(attachment.Name)
		local usedspringlength
		local isFront
		local usedwheelspeed

		if attachment.Name == "FL" or attachment.Name == "FR" then
			usedspringlength = frontspringlength
			isFront = true
			usedwheelspeed = frontwheelSpeed
		else
			usedspringlength = rearspringlength
			isFront = false
			usedwheelspeed = rearwheelSpeed
		end

		if not wheel then
			wheel = rep.Wheel:Clone()
			wheel.Parent = wheels
			wheel.Name = attachment.Name
			wheel.SteeringAttachment.RigidConstraint.Attachment1 = attachment
			return
		end

		local wheelRadius = (wheel.AppearanceWheel.WheelMesh.Size.Y + wheel.AppearanceWheel.WheelMesh.Size.Z)/4.44

		local raycastParams = RaycastParams.new()
		raycastParams.FilterType = Enum.RaycastFilterType.Exclude
		raycastParams.FilterDescendantsInstances = {car.Parent}
		local raycastresult = workspace:Raycast(attachment.WorldPosition, physics.CFrame.UpVector * Vector3.new(-usedspringlength,-usedspringlength,-usedspringlength), raycastParams)

		local upforce = 0
		local normal = Vector3.new(0,0,0)
		local grip = Vector3.new(0,0,0)
		local frictionweight = 0.01

		if raycastresult ~= nil then
			wheel.ForceAttachment.WorldPosition = raycastresult.Position

			local worldvelocity = wheel.Velocity
			local localvelocity = wheel.CFrame:vectorToObjectSpace(wheel.Velocity)
			local velocityup = localvelocity.Y
			local velocityfront = localvelocity.Z
			local velocityright = localvelocity.X

			-----------------------------------------------------------------------------------------SPRING
			local distance = (raycastresult.Position - attachment.WorldPosition).Magnitude
			local difference = math.max((usedspringlength - 1) - (distance), 0)
			local springforce = difference * springstrength
			local distance = (raycastresult.Position - attachment.WorldPosition).Magnitude
			local difference = math.max((usedspringlength - 1) - (distance), 0)
			local springforce = difference * springstrength
			--local damperforce = (worldvelocity.Y * damperstrength) --old damper system

			--[[local usedlastspringdist = lastspringdist[attachment.Name]
			if not usedlastspringdist then
				lastspringdist[attachment.Name] = difference
				return
			end

			local springspeed = (usedlastspringdist - difference)/deltaMulti
			local damperforce = springspeed * damperstrength

			lastspringdist[attachment.Name] = difference]] --old damper system 2

			local damperforce = velocityup * damperstrength

			upforce = springforce - damperforce
			normal = raycastresult.Normal

			if distance < springlowerlimit then --suspension bottoming out
				upforce *= (2 * math.abs(distance - springlowerlimit)) + 1
			end
			-----------------------------------------------------------------------------------------

			-----------------------------------------------------------------------------------------FRICTION
			frictionweight = math.max(upforce/2400, 0.01)

			local addedFriction = friction * frictionweight
			local frictionIncreasebySpeed = -0.005 * carSpeedFront + 0.8

			local slip = wheel.CFrame:vectorToWorldSpace((-localvelocity - Vector3.new(0,0,usedwheelspeed)) * Vector3.new(1,0,1)) --multiply by y by 0 is so it doesnt have a damping effect
			local friccurve = frictionCurve(slip.Magnitude) * addedFriction * frictionIncreasebySpeed
			grip = slip * friccurve

			local fricmulti = (friccurve / ((frictionCurve(0)) * addedFriction)) * frictionIncreasebySpeed--divides by the maxima y value
			if isFront then
				averagefrontfriction.Value += fricmulti + 0.07
			else
				averagerearfriction.Value += fricmulti + 0.07
			end
			-----------------------------------------------------------------------------------------

			-----------------------------------------------------------------------------------------MESH
			wheel.Mesh.Position = raycastresult.Position
			wheel.Mesh.CFrame = CFrame.new(wheel.Mesh.Position, wheel.Mesh.Position + normal)

			wheel.AppearanceWheel.Position = raycastresult.Position + (attachment.WorldPosition - raycastresult.Position).Unit * wheel.AppearanceWheel.WheelMesh.Size.Y/2
			wheel.AppearanceWheel.Orientation = wheel.Orientation
			-----------------------------------------------------------------------------------------

			-----------------------------------------------------------------------------------------SOUNDS
			local localsoundslip = ((-localvelocity * Vector3.new(1,0,1) - Vector3.new(0,0,usedwheelspeed)).Magnitude)
			if soundslip < localsoundslip then
				soundslip = localsoundslip
			end
			-----------------------------------------------------------------------------------------
		else
			local wheelVector = physics.CFrame.UpVector * Vector3.new(-usedspringlength,-usedspringlength,-usedspringlength)
			local wheelPoint = wheel.Position + wheelVector

			wheel.Mesh.Position = wheelPoint
			wheel.Mesh.CFrame = CFrame.new(wheel.Mesh.Position, wheel.Mesh.Position + normal)

			wheel.AppearanceWheel.Position = wheelPoint + (attachment.WorldPosition - wheelPoint).Unit * wheel.AppearanceWheel.WheelMesh.Size.Y/2
			wheel.AppearanceWheel.Orientation = wheel.Orientation
		end

		-----------------------------------------------------------------------------------------FORCE
		attachment.SpringForce.Force = Vector3.new(0,upforce*0.3,0)
		wheel.ForceAttachment.SurfaceForce.Force = (normal * upforce) + (grip)
		-----------------------------------------------------------------------------------------

		-----------------------------------------------------------------------------------------MESH
		local flip = 0

		if attachment.Name == "FR" or attachment.Name == "RR" then
			flip = 180
		end

		local rollWheelSpeed
		if isFront then
			rollWheelSpeed = frontwheelSpeed
		else
			rollWheelSpeed = rearwheelSpeed
		end

		local roll = wheel.AppearanceWheel.Roll
		roll.Value += (-rollWheelSpeed)/wheelRadius * deltaMulti
		if roll.Value > 360 then
			roll.Value = roll.Value - 360
		elseif roll.Value < 0 then
			roll.Value = roll.Value + 360
		end
		wheel.AppearanceWheel.RollAttachment.CFrame = CFrame.fromOrientation(math.rad(wheel.AppearanceWheel.Roll.Value),0,math.rad(flip)) + wheel.AppearanceWheel.RollAttachment.CFrame.Position

		wheel.AppearanceWheel.WheelMesh.Blur.Transparency = math.clamp(-0.015 * math.abs(rollWheelSpeed/wheelRadius * 1.5) + 1, 0, 1)
		-----------------------------------------------------------------------------------------

		-----------------------------------------------------------------------------------------STEERING
		local steerfloat = seatPart.SteerFloat

		steeringspeed += math.clamp(steerfloat * steeringaccel * (deltaMulti^2), -steeringmaxspeed * deltaMulti, steeringmaxspeed * deltaMulti)
		steeringspeed *= (steeringdecay ^ deltaMulti)

		if math.abs(steeringangle) >= steeringmaxangle then
			if steerfloat == 0 then
				steeringspeed = 0
			elseif steerfloat > 0 then
				math.clamp(steeringspeed, -steeringmaxspeed, 0)
			elseif steerfloat < 0 then
				math.clamp(steeringspeed, 0, steeringmaxspeed)
			end
		end

		steeringangle = math.clamp(steeringangle + steeringspeed,-steeringmaxangle, steeringmaxangle)
		steeringangle = steeringangle * ((-steeringSpeedDecay * (car.Physics.AssemblyLinearVelocity.Magnitude) + 1) ^ deltaMulti)

		car.Physics.FL.CFrame = CFrame.fromOrientation(math.rad(0),math.rad(-steeringangle/10),math.rad(0))+car.Physics.FL.CFrame.Position
		car.Physics.FR.CFrame = CFrame.fromOrientation(math.rad(0),math.rad(-steeringangle/10),math.rad(0))+car.Physics.FR.CFrame.Position
		-----------------------------------------------------------------------------------------
	end

	averagerearfriction.Value = math.clamp(averagerearfriction.Value, 0, 1.5) --last value is the amount of driven wheels
	averagefrontfriction.Value = math.clamp(averagefrontfriction.Value, 0, 1.5)

	paleovelocity = carSpeed.Magnitude
end)


carfunc2 = userinputservice.InputBegan:Connect(function(input, isProcessed)
	handleInput(input, 1)

	if not isProcessed then

		if input.KeyCode == Enum.KeyCode.LeftShift then
			tweenService:Create(clutch, TweenInfo.new(0.2), {Value = 0}):Play()

		elseif input.KeyCode == Enum.KeyCode.W  or input.KeyCode == Enum.KeyCode.Up then
			tweenService:Create(engineThrottle, TweenInfo.new(0.2), {Value = 1}):Play()

		elseif input.KeyCode == Enum.KeyCode.S  or input.KeyCode == Enum.KeyCode.Down then
			tweenService:Create(braking, TweenInfo.new(0.2), {Value = brakeForce}):Play()

		elseif input.KeyCode == Enum.KeyCode.E then
			gearShift(1)
		elseif input.KeyCode == Enum.KeyCode.Q then
			gearShift(-1)

		elseif input.KeyCode == Enum.KeyCode.LeftControl then
			pbrake = 0
		elseif input.KeyCode == Enum.KeyCode.N then
			toggleModelDebug()
		end
	end
end)

carfunc3 = userinputservice.InputEnded:Connect(function(input, isProcessed)
	handleInput(input, 0)


	if input.KeyCode == Enum.KeyCode.LeftShift then
		tweenService:Create(clutch, TweenInfo.new(0.2), {Value = maxClutch}):Play()

	elseif input.KeyCode == Enum.KeyCode.W  or input.KeyCode == Enum.KeyCode.Up then
		tweenService:Create(engineThrottle, TweenInfo.new(0.2), {Value = 0}):Play()

	elseif input.KeyCode == Enum.KeyCode.S  or input.KeyCode == Enum.KeyCode.Down then
		tweenService:Create(braking, TweenInfo.new(0.2), {Value = 1}):Play()

	elseif input.KeyCode == Enum.KeyCode.LeftControl then
		pbrake = 1

	end

end)

end)

2 Likes

change it to while wont solve your problem. Turn it back to renderstepped and facor in the deltaTime argument of the renderStepped function. This give the time passes between frames.

You should make all of your variable that change in RenderStepped to changed in 1 second. Then multiply it to the deltaTime for the correct result that is not frame rate dependent.

1 Like

like that?
image

Like this:
for example, you want to decrease a number by 5 in one second, and you don’t want it to be frame rate dependent. You do this:

runService.RenderStepped:Connect(function(dt)
    number = number - 5*deltaTime
end)
1 Like

ok, so I need to do this for each variable value??

THe value that change every frame

1 Like

like this?
image
Sorry if I’m being a little slow to understand things, I’m a little inexperienced with this type of script

1 Like

Yea, deltaMulti is the value you change

1 Like

robloxapp-20240627-2350216.wmv (934.7 KB)
now the wheels is bugged

I looked at the script output and noticed some errors

the line:

why do you use deltaMulti, multiply it the value with deltaTime, and why do you ^2 it anyway. You got me wrong

1 Like

Sorry, I still don’t understand what I should do exactly?

Hey, sorry but this isn’t something that can really be fixed. You can do some complex math to make it better but it will never be fixed.

This is a common issue with systems like this in roblox. Even Jailbreak suffers from it due to their vehicle system using similar tactics.
image

The reason behind this is because roblox physics run at 240 frames per second, but the fastest Roblox allows you to run code is 60 times per second (or whatever the client’s framerate is). This means there are physics frames where the suspension can’t update, so the suspension force pushing up on the vehicle becomes inaccurate and the vehicle starts to bounce. This isn’t an issue at 60 FPS, but the lower the framerate, the less times the suspension can update.
People have been asking Roblox to solve this issue for years.

2 Likes

Yep this is correct.

To add more info though the tech we need is physics substep, which is manually introducing more frames for physics

The complicated math for this is to do it manually which is a problem as you need to calculate the forces in the future in which the frames are missing in order to account for it.

Ive done it for linear acceleration but including rotation will make it twice as difficult.

2 Likes

huh, how do I at least reduce this? sorry I really don’t understand

Sorry but the solution is about as complex as it sounds. I highly suggest you just use the built-in spring constraint instead. If you want the springs to be bouncy you can try lowering the gravity.
If you really want to keep using the ray casts, dthecoolest’s post explains probably the best solution you can get but it will probably be pretty difficult.

If you do chose to use spring constraints I suggest searching up something along the line of “how to set up car chassis” on the DevForum and you should be able to find a decent tutorial.
I would help you more but I don’t really have much time to, this should point you in the right direction though

1 Like

I tried this last week and actually the constraint suspension is very similar to the raycsting one, the problem is that the car rolls over just by turning a little at high speeds with low gravity

If I add more weight the car sits lower so I increase the suspension force and it doesn’t get smoother

robloxapp-20240628-1639100.wmv (2.6 MB)

This happens with all cars, the situation gets worse when it’s an SUV or bus.

I made some changes to the chassis and it stopped rolling, thank you very much for all the help you provided me!

and sorry for the confusion… I’m not very good at raycsting scripts

1 Like

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