I have a very specific problem and I am looking for help finding a workaround, up until now I have been using a car suspension system based on spring constraints, which while functional was sub optimal.
After researching I was able to find a solid chunk of code to use for my Vehicles but it has a few issues,
Properties Module:
local module = {
Wingman = {
SuspensionMaxLength = 2.8,
wheelRadius = 1.5,
Stiffness = 120,
Damper = 6,
wheelFriction = 5.5,
torque = 30,
MaxSpeed = 90,
SteerAngle = 30,
WheelPositions = {
FLwheel = Vector3.new(3.424, 0, 6.117),
FRwheel = Vector3.new(-3.438, 0, 6.117),
RLwheel = Vector3.new(3.423, 0, -5.767),
RRwheel = Vector3.new(-3.438, 0, -5.75),
},
},
--here its possible to copy table above and make more cars just this simply
}
return module
Main Code:
local CarPrim = Seat.Parent.PrimaryPart
local CarModel = Seat.Parent
local SpringLengthMemory = {}
for i,v in pairs(props.WheelPositions)do SpringLengthMemory[i] = 0.5 end
coroutine.wrap(function()
while Connnection ~= Seat do
local delta = game["Run Service"].Heartbeat:Wait()
for wheelName, originalPosition in pairs(props.WheelPositions)do
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
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 RotationsOnlyWheelDirCFrame = CFrame.lookAt(Vector3.zero,carCFrame.LookVector,carCFrame.UpVector)
local LocalVelocity = RotationsOnlyWheelDirCFrame:ToObjectSpace(CFrame.new(CarPrim:GetVelocityAtPosition(raycast.Position)))
local Xforce = RotationsOnlyWheelDirCFrame.RightVector * -LocalVelocity.x * props.wheelFriction
local Zforce = RotationsOnlyWheelDirCFrame.LookVector * Seat.ThrottleFloat * props.torque * (math.sign(-LocalVelocity.z)==Seat.Throttle and(1 - math.min(1,math.abs(LocalVelocity.z)/props.MaxSpeed))or 1)
SpringLengthMemory[wheelName] = SpringLength
CarPrim:ApplyImpulseAtPosition(SuspensionForceVec3 + Xforce + Zforce, raycast.Position)
else
SpringLengthMemory[wheelName] = props.SuspensionMaxLength
end
end
wait()
end
end) ()
(Video I sourced the Code from)
The person who was initially using this code had a custom system for the wheels, the wheels were not physics based and instead simply welded to the car, with him applying velocity to the car itself for movement instead of the wheels.
I however have a physics based system using CylindricalConstraints as the motors for the wheels:
And that’s where the problem is, :ApplyImpulseAtPosition()
doesn’t work for my car’s wheels (at least not in the way this code handles it), When I try to run it the car just starts bouncing all over the place and doesn’t appreciate life very much.
If anyone can help think of a way to modify the code into working, while also keeping the wheels the way they are I would appreciate that greatly.