-
I have some problems with the raycast suspensions. I have this raycast suspension system, I didn’t write it, I got help, because I tried watching tutorials and searching for tutorials, but nothing, I still can’t understand how they work.
-
The first issue is: The suspensions don’t really work, beucase on a terrain with rocks, the car gets stuck really easily, and on a grass terrain also gets stuck when the terrain is not flat. I tried searching the solution but nothing.
The second issue is: Whenever I exit the vehicle, all the car parts get destroyed, but the scripts and the parent models are still in the workspace (There’s no destroy script). -
I have tried searching the solutions and searching tutorials to learn more about raycast suspensions, but I still can’t adress the solution for these 2 problems.
Server script:
local car = script.Parent
local remoteEvent = script.Parent:WaitForChild("CarMovementEvent")
local CarUI = script.Parent:WaitForChild("CarUI")
local wheel1 = car.FrontLeft.Wheel
local wheel2 = car.FrontRight.Wheel
local wheel3 = car.BackLeft.Wheel
local wheel4 = car.BackRight.Wheel
local moveDamping = 10
local rotateDamping = 12
local suspensionHeight = 2
local suspensionLength = 5
local variablesModule = require(script.Parent:WaitForChild("GlobalVariables"))
local function smoothMove(position, targetPos, damping)
return position + (targetPos - position) * damping
end
local function smoothRotate(rotation, targetRot, damping)
return rotation:lerp(targetRot, damping)
end
remoteEvent.OnServerEvent:Connect(function(player, targetPos, targetRot)
car.Position = smoothMove(car.Position, targetPos, moveDamping)
car.Rotation = smoothRotate(car.Rotation, targetRot, rotateDamping)
end)
local function updateWheelSuspension(deltaTime, wheel)
if not car.VehicleSeat.Occupant then return end
local raycastParams = RaycastParams.new()
raycastParams.FilterDescendantsInstances = {car}
raycastParams.FilterType = Enum.RaycastFilterType.Blacklist
local currentPosition = wheel.CFrame.Position
local hitInfo = workspace:Raycast(wheel.Position, Vector3.new(0, -suspensionLength, 0), raycastParams)
if hitInfo then
local position = hitInfo.Position
local normal = hitInfo.Normal
local suspensionDistance = (position - currentPosition).Magnitude
if suspensionDistance < suspensionHeight + suspensionLength then
local targetPosition = position + normal * (suspensionHeight + suspensionLength - suspensionDistance)
local springConstant = 150
local damping = 0.1
local springForce = (targetPosition - currentPosition) * springConstant
local dampingForce = wheel.Velocity * damping
local resultantForce = springForce - dampingForce
local forceMagnitude = math.min(resultantForce.Magnitude, 1000)
resultantForce = resultantForce.unit * forceMagnitude
wheel:ApplyImpulse(resultantForce)
end
end
end
local function updateSuspensions(deltaTime)
if not car.VehicleSeat.Occupant then return end
updateWheelSuspension(deltaTime, wheel1)
updateWheelSuspension(deltaTime, wheel2)
updateWheelSuspension(deltaTime, wheel3)
updateWheelSuspension(deltaTime, wheel4)
end
game["Run Service"].Heartbeat:Connect(updateSuspensions)
local function stopVehicleMotion()
for _, part in pairs(car:GetDescendants()) do
if part:IsA("BasePart") then
part.Velocity = Vector3.new(0, 0, 0)
part.AssemblyAngularVelocity = Vector3.new(0, 0, 0)
end
end
end
local function EmergencyStop()
wheel1.WheelConstraint.AngularVelocity = 0
wheel2.WheelConstraint.AngularVelocity = 0
wheel3.WheelConstraint.AngularVelocity = 0
wheel4.WheelConstraint.AngularVelocity = 0
end
local function disableWheelForces()
for _, wheel in ipairs(car:GetChildren()) do
if wheel:IsA("Weld") then
wheel.Enabled = false
end
end
end
local function stabilizeVehicle()
car.PrimaryPart.Anchored = true
wait(0.1)
car.PrimaryPart.Anchored = false
end
local minAngle,maxAngle = -130,60
local totalDegrees = maxAngle-minAngle
local gearSettings = {
gear1MaxSpeed = 15,
gear2MaxSpeed = 30,
gear3MaxSpeed = 45,
gear4MaxSpeed = 60,
gear5MaxSpeed = 70
}
local currentGear = "gear1"
local function calculateDegree(speed)
local speedPerDegree = speed/gearSettings[currentGear.."MaxSpeed"]
return math.min(minAngle+speed*speedPerDegree,maxAngle)
end
local function SpeedOmeter(player, speed)
if speed <= -0 then
speed = 0 - speed
end
local speedOmeterUI = player.PlayerGui.CarUI.Speedometer
local deg = calculateDegree(speed)
speedOmeterUI.ForegroundCircle.Rotation = deg
speedOmeterUI.Speed.Text = speed.." KMH"
end
car.VehicleSeat:GetPropertyChangedSignal("Occupant"):Connect(function()
if car.VehicleSeat.Occupant then
local occupant = car.VehicleSeat.Occupant
local player = game.Players:FindFirstChild(occupant.Parent.Name)
print(occupant, occupant.Parent.Name, player)
local carUIClone = CarUI:Clone()
carUIClone.Parent = player:WaitForChild("PlayerGui")
else
EmergencyStop()
end
end)
local seat = car.VehicleSeat
local maxSteeringAngle = 60
local steeringDamping = 0.05
local isInNeutral = true
local neutralAngle = 0
local steeringSensitivity = 0.05
local function smoothSteer(steerInput, currentAngle)
local targetAngle = steerInput * maxSteeringAngle
local angleDifference = targetAngle - currentAngle
local damping = angleDifference * steeringDamping
currentAngle = currentAngle + damping
return math.clamp(currentAngle, -maxSteeringAngle, maxSteeringAngle)
end
local function lerp(a, b, t)
return a + (b - a) * t
end
local function updateSteering(steerInput, currentAngle)
local speed = seat.CFrame.LookVector:Dot(seat.Velocity)
local maxSteeringAngle = speed > 10 and 30 or 15
local targetAngle = steerInput * maxSteeringAngle
if steerInput == 0 then
return lerp(currentAngle, 0, 0.2)
end
local angleDifference = targetAngle - currentAngle
local damping = angleDifference * steeringDamping
currentAngle = currentAngle + damping
return math.clamp(currentAngle, -maxSteeringAngle, maxSteeringAngle)
end
game:GetService("RunService").Heartbeat:Connect(function()
if car.VehicleSeat.Occupant then
local occupant = car.VehicleSeat.Occupant
local player = game.Players:FindFirstChild(occupant.Parent.Name)
SpeedOmeter(player, math.round(seat.CFrame.LookVector:Dot(seat.Velocity)))
end
local steerInput = seat.Steer
local currentAngle1 = wheel1.Parent.PartB.SteeringConstraint.TargetAngle or 0
local currentAngle2 = wheel2.Parent.PartB.SteeringConstraint.TargetAngle or 0
local newAngle1 = updateSteering(steerInput, currentAngle1)
local newAngle2 = updateSteering(steerInput, currentAngle2)
wheel1.Parent.PartB.SteeringConstraint.TargetAngle = newAngle1
wheel2.Parent.PartB.SteeringConstraint.TargetAngle = newAngle2
end)
local speed = 300
local currentAngularVelocity = 0
local function smoothAngularVelocity(targetVelocity, deltaTime)
return currentAngularVelocity + ((targetVelocity - currentAngularVelocity) * 0.1 * deltaTime)
end
seat:GetPropertyChangedSignal("Throttle"):Connect(function()
local targetAngularVelocity
if seat.Throttle >= 1 then
local deltaTime = game["Run Service"].Heartbeat:Wait()
currentAngularVelocity = 1
currentAngularVelocity = math.clamp(currentAngularVelocity + ((seat.Throttle * speed) - currentAngularVelocity) * 0.1, -speed, speed)
wheel1.WheelConstraint.AngularVelocity = currentAngularVelocity
wheel2.WheelConstraint.AngularVelocity = currentAngularVelocity * -1
wheel3.WheelConstraint.AngularVelocity = currentAngularVelocity
wheel4.WheelConstraint.AngularVelocity = currentAngularVelocity * -1
elseif seat.Throttle == 0 then
wheel1.WheelConstraint.AngularVelocity = 0
wheel2.WheelConstraint.AngularVelocity = 0
wheel3.WheelConstraint.AngularVelocity = 0
wheel4.WheelConstraint.AngularVelocity = 0
elseif seat.Throttle <= -1 then
local deltaTime = game["Run Service"].Heartbeat:Wait()
currentAngularVelocity = math.clamp(currentAngularVelocity + ((seat.Throttle * -speed) - currentAngularVelocity) * 0.1, -speed, -speed)
wheel1.WheelConstraint.AngularVelocity = currentAngularVelocity
wheel2.WheelConstraint.AngularVelocity = currentAngularVelocity * -1
wheel3.WheelConstraint.AngularVelocity = currentAngularVelocity
wheel4.WheelConstraint.AngularVelocity = currentAngularVelocity * -1
end
end)
local function maintainWheelAttachment()
if not car.VehicleSeat.Occupant then return end
while true do
if not wheel1:IsDescendantOf(car) then
wheel1.Parent = car
end
if not wheel2:IsDescendantOf(car) then
wheel2.Parent = car
end
if not wheel3:IsDescendantOf(car) then
wheel3.Parent = car
end
if not wheel4:IsDescendantOf(car) then
wheel4.Parent = car
end
wait(1)
end
end
task.spawn(maintainWheelAttachment)
Client script:
local car = script.Parent
local remoteEvent = script.Parent:WaitForChild("CarMovementEvent")
while true do
if script.Parent.VehicleSeat.Occupant == nil then return end
local targetPos = car.Position
local targetRot = car.Rotation
remoteEvent:FireServer(targetPos, targetRot)
wait()
end
I hope someone can help me. Thank you.