Ello i made a Raycast suspension car with the help both these unity videos:
video number 1
video number 2
the reason why i am asking for a code review is because while play testing it the controls kinda feel weird.
–Main suspension script–
local Part = game.Players.LocalPlayer.Character
local run = game:GetService("RunService")
local rep = game:GetService('ReplicatedStorage')
local contextActionService = game:GetService("ContextActionService")
local WheelBase = Part:GetAttribute("wheelBase")
local rearTrack = Part:GetAttribute("rearTrack")
local turnRadious = Part:GetAttribute("turnRadious")
local SteeringInput = require(rep.Steering).init(WheelBase, rearTrack, turnRadious)
local leftValue, rightValue = 0, 0
local driveValeF, driveValeB = 0, 0
local fx = 0
local fy = 0
local wheelVelocity = Vector3.zero
function quadraticBezier(t, p0, p1, p2)
return (1 - t)^2 * p0 + 2 * (1 - t) * t * p1 + t^2 * p2
end
local function onLeft(actionName, inputState)
if inputState == Enum.UserInputState.Begin then
leftValue = 1
elseif inputState == Enum.UserInputState.End then
leftValue = 0
end
end
local function onRigth(actionName, inputState)
if inputState == Enum.UserInputState.Begin then
rightValue = 1
elseif inputState == Enum.UserInputState.End then
rightValue = 0
end
end
local function onDriveF(actionName, inputState)
if inputState == Enum.UserInputState.Begin then
driveValeF = 1
elseif inputState == Enum.UserInputState.End then
driveValeF = 0
end
end
local function onDriveB(actionName, inputState)
if inputState == Enum.UserInputState.Begin then
driveValeB = 1
elseif inputState == Enum.UserInputState.End then
driveValeB = 0
end
end
local cframe = Part.PrimaryPart.CFrame
for _, attach in pairs(Part.PrimaryPart:GetChildren()) do
if attach:IsA("Attachment") then
local function onUpdate()
local moveDirection = rightValue - leftValue
local driveDir = driveValeF - driveValeB
--SUSPENSION--
local Heigth = Part.PrimaryPart:GetAttribute("Heigth")
local Stiffness = Part.PrimaryPart:GetAttribute("Stiffness")
local Damping = Part.PrimaryPart:GetAttribute("Damping")
local Mass = Part.PrimaryPart:GetAttribute("Mass")
local ackmRigth = Part:GetAttribute('ackmRight')
local ackmLeft = Part:GetAttribute('ackmLeft')
local Grip = Part:GetAttribute("Grip")
local carTopSpeed = Part:GetAttribute("carTopSpeed")
local org = attach.WorldCFrame.Position
local dir = -attach.CFrame.UpVector * Heigth
local rayParmas = RaycastParams.new()
rayParmas.FilterType = Enum.RaycastFilterType.Blacklist
rayParmas.FilterDescendantsInstances = {Part}
local raycast = workspace:Raycast(org, dir, rayParmas)
SteeringInput:Update(moveDirection, Part)
--wheelRot--
if string.sub(attach.Name, 1, 1) == 'F' then
attach.Orientation = Vector3.new(0,Part:GetAttribute("steerAngle"), 0)
end
if raycast then
local dist = (org - raycast.Position).Magnitude
local worldVel = Part.PrimaryPart:GetVelocityAtPosition(org)
--World space directons
local springDir = cframe.UpVector
local offset = Heigth - dist
local vel = springDir:Dot(worldVel)
local force = ((offset * Stiffness) - (vel * Damping)) * Mass
Part.PrimaryPart:ApplyImpulseAtPosition(springDir * force, org)
end
if raycast then
if string.sub(attach.Name, 1, 1) == 'F' then
local steerDir = attach.WorldCFrame.RightVector
local steerOrg = attach.WorldPosition
local tireWorldDir = Part.PrimaryPart:GetVelocityAtPosition(steerOrg)
local vel = steerDir:Dot(tireWorldDir)
local desigredValueChange = -vel * Grip
local desigredAccel = desigredValueChange
Part.PrimaryPart:ApplyImpulseAtPosition(steerDir * 5* desigredAccel, steerOrg)
end
end
if raycast then
if string.sub(attach.Name, 1, 1) == 'B' then
local accDir = attach.WorldCFrame.LookVector
local carSpeed = accDir:Dot(Part.PrimaryPart.AssemblyLinearVelocity)
local norSpeed = math.clamp(math.abs(carSpeed)/carTopSpeed, 0, 1)
local avaibleToruq = quadraticBezier(norSpeed, 5, 10, 3) * driveDir
Part.PrimaryPart:ApplyImpulseAtPosition(accDir * avaibleToruq, org)
end
end
end
run:BindToRenderStep('Control', Enum.RenderPriority.Input.Value, onUpdate)
end
end
contextActionService:BindAction('Left', onLeft, false, Enum.KeyCode.A)
contextActionService:BindAction('Rigth', onRigth, false, Enum.KeyCode.D)
contextActionService:BindAction('DriveF', onDriveF, false, Enum.KeyCode.W)
contextActionService:BindAction('DriveB', onDriveB, false, Enum.KeyCode.S)
– Ackermann Steering–
local Steering = {}
local MT = {__index = Steering}
local ackmLeft = nil
local ackmRight = nil
function Steering.init(wheelBase, rearTrack, turnRadious)
local self = {}
self.wheelBase = wheelBase
self.rearTrack = rearTrack
self.turnRadious = turnRadious
return setmetatable(self, MT)
end
function Steering:Update(steeringInput, model: Model)
local steerInput = steeringInput
if steeringInput > 0 then
ackmLeft = math.deg(math.atan(self.wheelBase / (self.turnRadious + self.rearTrack / 2))) * steeringInput
ackmRight = math.deg(math.atan(self.wheelBase / (self.turnRadious - self.rearTrack / 2))) * steeringInput
model:SetAttribute("ackmLeft", ackmLeft)
model:SetAttribute("ackmRight", ackmRight)
for _, wheel in pairs(model.PrimaryPart:GetChildren()) do
if wheel:GetAttribute("frontWheelLeft") then
model:SetAttribute("steerAngle", ackmLeft)
end
if wheel:GetAttribute("frontWheelRight") then
model:SetAttribute("steerAngle", ackmRight)
end
end
elseif steeringInput < 0 then
ackmLeft = math.deg(math.atan(self.wheelBase / (self.turnRadious - self.rearTrack / 2)))
ackmRight = math.deg(math.atan(self.wheelBase / (self.turnRadious + self.rearTrack / 2))) * steeringInput
model:SetAttribute("ackmLeft", ackmLeft)
model:SetAttribute("ackmRight", ackmRight)
for _, wheel in pairs(model.PrimaryPart:GetChildren()) do
if wheel:GetAttribute("frontWheelLeft") then
model:SetAttribute("steerAngle", ackmLeft)
end
if wheel:GetAttribute("frontWheelRight") then
model:SetAttribute("steerAngle", ackmRight)
end
end
else
ackmLeft = 0
ackmRight = 0
model:SetAttribute("ackmLeft", ackmLeft)
model:SetAttribute("ackmRight", ackmRight)
for _, wheel in pairs(model.PrimaryPart:GetChildren()) do
if wheel:GetAttribute("frontWheelLeft") then
model:SetAttribute("steerAngle", ackmLeft)
end
if wheel:GetAttribute("frontWheelRight") then
model:SetAttribute("steerAngle", ackmRight)
end
end
end
end
return Steering
–Project file–
funnyCars.rbxl (49.7 KB)