-
**What do you want to achieve?
a stable chassis. -
**What is the issue?
the chassis shakes and jumps uncontrollably when the player has low fps. -
**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
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)