This seems like the type of thing that has happened before, but I haven’t been able to find a forum post for it yet - if there’s an existing post addressing this issue, please link me to it!
I’m trying to make a vehicle in Roblox Studio, and have created a decent framework for accelerating, decelerating, and reversing. But when I steer the vehicle, it moves along a linear axis in the direction of where it is being steered (seen below).
Things I know don’t work:
- Creating a differential between the two rear wheels
Subtracting a defined speed from the inner rear wheel’s angular velocity. Currently using a differential in that the rear left and rear right wheels use separate axles, both of which are acted upon by individual angular velocities that allow it to drive forward/reverse, but there is nothing constraining the two wheels/axles to the same angular velocity (they should be able to spin independently of one another) - Using an angular velocity to “assist” (force) the vehicle to turn
Technically worked, but the turning was very snappy and not what I was looking for. I’d like to refrain from using cheaty solutions like this
Information
The front wheels are unpowered and spin freely, their steering angle determined by a hinge with a servo. The rear wheels are powered, welded to their respective axle which is acted upon by an angular velocity allowing it to spin.
Script (activated by another script when a user enters the driver’s seat, disabled on exit)
script.Starting:Play() -- engine start sound
wait(script.Starting.TimeLength - .5)
script.Idle:Play() -- engine idle sound
script.Parent.Parent.AxleRR.AngularVelocity.AngularVelocity = Vector3.new(script.Vars.Gears.Base.Value, 0, 0) -- setting proper velocities as defined in the Vars folder under the script
script.Parent.Parent.AxleRL.AngularVelocity.AngularVelocity = Vector3.new(script.Vars.Gears.Base.Value, 0, 0) -- setting proper velocities as defined in the Vars folder under the script
local tireFriction = script.Vars.TireGrip.Value -- unused
local gear = 1 -- current gear
local forwards = true
local steering = false
local function brake()
script.Parent.Parent.AxleRR.AngularVelocity.Enabled = false
script.Parent.Parent.AxleRL.AngularVelocity.Enabled = false
script.Parent.Parent.BrakeDisc.CanCollide = true
for i,v in pairs(script.Parent.Parent.BrakeLights:GetChildren()) do
if v.ClassName == "Part" then
v.Material = Enum.Material.Neon
end
end
end
local function offBrake()
script.Parent.Parent.AxleRR.AngularVelocity.Enabled = false
script.Parent.Parent.AxleRL.AngularVelocity.Enabled = false
script.Parent.Parent.BrakeDisc.CanCollide = false
for i,v in pairs(script.Parent.Parent.BrakeLights:GetChildren()) do
if v.ClassName == "Part" then
v.Material = Enum.Material.Glass
end
end
for i,v in pairs(script.Parent.Parent.ReverseLights:GetChildren()) do
if v.ClassName == "Part" then
v.Material = Enum.Material.Glass
end
end
end
local function accelerateF()
offBrake()
forwards = true
script.Parent.Parent.AxleRR.AngularVelocity.AngularVelocity = Vector3.new(math.abs(script.Parent.Parent.AxleRR.AngularVelocity.AngularVelocity.X), 0, 0) -- make it forwards
script.Parent.Parent.AxleRR.AngularVelocity.Enabled = true -- start applying force
script.Parent.Parent.AxleRL.AngularVelocity.AngularVelocity = Vector3.new(math.abs(script.Parent.Parent.AxleRL.AngularVelocity.AngularVelocity.X), 0, 0) -- same thing with the other axle
script.Parent.Parent.AxleRL.AngularVelocity.Enabled = true
end
local function accelerateR()
offBrake()
forwards = false
script.Parent.Parent.AxleRR.AngularVelocity.AngularVelocity = Vector3.new(-math.abs(script.Parent.Parent.AxleRR.AngularVelocity.AngularVelocity.X), 0, 0) -- make it backwards
script.Parent.Parent.AxleRR.AngularVelocity.Enabled = true -- start applying force
script.Parent.Parent.AxleRL.AngularVelocity.AngularVelocity = Vector3.new(-math.abs(script.Parent.Parent.AxleRL.AngularVelocity.AngularVelocity.X), 0, 0) -- same thing with the other axle
script.Parent.Parent.AxleRL.AngularVelocity.Enabled = true
for i,v in pairs(script.Parent.Parent.ReverseLights:GetChildren()) do
if v.ClassName == "Part" then
v.Material = Enum.Material.Neon
end
end
end
script.Parent.Changed:Connect(function(prop)
if prop == "Throttle" then
if script.Parent.Throttle == 1 then -- pressing W
if not forwards and script.Parent.Parent.AxleRR.AssemblyAngularVelocity.Magnitude > .1 then -- going backwards
if script.Parent.Parent.AxleRR.AssemblyAngularVelocity.Magnitude < .5 and script.Parent.Parent.AxleRR.AssemblyAngularVelocity.Magnitude > -.5 then -- moving slowly
brake()
else
brake()
end
else -- going forward or stopped
accelerateF()
end
elseif script.Parent.Throttle == -1 then -- pressing S
if forwards and script.Parent.Parent.AxleRR.AssemblyAngularVelocity.Magnitude > .1 then -- going forwards
if script.Parent.Parent.AxleRR.AssemblyAngularVelocity.Magnitude < .5 and script.Parent.Parent.AxleRR.AssemblyAngularVelocity.Magnitude > -.5 then -- moving slowly
brake()
else
brake()
end
else -- going backwards or stopped
accelerateR()
end
else -- no input
if script.Parent.Parent.AxleRR.AssemblyAngularVelocity.Magnitude < .5 and script.Parent.Parent.AxleRR.AssemblyAngularVelocity.Magnitude > -.5 then -- moving slowly
brake()
else
offBrake()
end
end
elseif prop == "Steer" then
if script.Parent.Steer == 1 then -- pressing D
steering = true
script.Parent.Parent.AxleF.FRSteerHinge.TargetAngle = script.Parent.Parent.AxleF.FRSteerHinge.UpperAngle
script.Parent.Parent.AxleF.FLSteerHinge.TargetAngle = script.Parent.Parent.AxleF.FLSteerHinge.UpperAngle
elseif script.Parent.Steer == -1 then -- pressing A
steering = true
script.Parent.Parent.AxleF.FRSteerHinge.TargetAngle = script.Parent.Parent.AxleF.FRSteerHinge.LowerAngle
script.Parent.Parent.AxleF.FLSteerHinge.TargetAngle = script.Parent.Parent.AxleF.FLSteerHinge.LowerAngle
else -- no input
steering = false
script.Parent.Parent.AxleF.FRSteerHinge.TargetAngle = 0
script.Parent.Parent.AxleF.FLSteerHinge.TargetAngle = 0
wait(script.Parent.Parent.AxleF.FRSteerHinge.UpperAngle/(script.Parent.Parent.AxleF.FRSteerHinge.AngularSpeed * 57.7) + .15)
end
end
end)
while script.Manual.Value == false do -- script for automatic transmission
wait(.25)
script.Idle.PlaybackSpeed = (script.Parent.Parent.AxleRR.AssemblyAngularVelocity.Magnitude / (script.Vars.Gears.Base.Value + script.Vars.Gears.AddedPG.Value * script.Vars.Gears.Value)) * 1.25 + 1
if forwards then
print(gear) -- debugging temporary
if script.Parent.Parent.AxleRR.AssemblyAngularVelocity.Magnitude > script.Parent.Parent.AxleRR.AngularVelocity.AngularVelocity.Magnitude - .45 and gear < script.Vars.Gears.Value then
wait(.45)
if script.Parent.Parent.AxleRR.AssemblyAngularVelocity.Magnitude > script.Parent.Parent.AxleRR.AngularVelocity.AngularVelocity.Magnitude - .45 then
gear += 1
script.Parent.Parent.AxleRR.AngularVelocity.AngularVelocity = Vector3.new(script.Parent.Parent.AxleRR.AngularVelocity.AngularVelocity.X + script.Vars.Gears.AddedPG.Value, 0, 0)
script.Parent.Parent.AxleRL.AngularVelocity.AngularVelocity = Vector3.new(script.Parent.Parent.AxleRL.AngularVelocity.AngularVelocity.X + script.Vars.Gears.AddedPG.Value, 0, 0)
script.Shift:Play()
end
elseif script.Parent.Parent.AxleRR.AssemblyAngularVelocity.Magnitude < (script.Vars.Gears.Base.Value + (script.Vars.Gears.AddedPG.Value * gear)) - script.Vars.Gears.AddedPG.Value - .45 and gear > 1 then
wait(.45)
if script.Parent.Parent.AxleRR.AssemblyAngularVelocity.Magnitude < (script.Vars.Gears.Base.Value + (script.Vars.Gears.AddedPG.Value * gear)) - script.Vars.Gears.AddedPG.Value - .45 then
gear -= 1
script.Parent.Parent.AxleRR.AngularVelocity.AngularVelocity = Vector3.new(script.Parent.Parent.AxleRR.AngularVelocity.AngularVelocity.X - script.Vars.Gears.AddedPG.Value, 0, 0)
script.Parent.Parent.AxleRL.AngularVelocity.AngularVelocity = Vector3.new(script.Parent.Parent.AxleRL.AngularVelocity.AngularVelocity.X - script.Vars.Gears.AddedPG.Value, 0, 0)
script.ShiftDown:Play()
end
end
else
gear = 1
script.Parent.Parent.AxleRR.AngularVelocity.AngularVelocity = Vector3.new(-script.Vars.Gears.Base.Value, 0, 0)
script.Parent.Parent.AxleRL.AngularVelocity.AngularVelocity = Vector3.new(-script.Vars.Gears.Base.Value, 0, 0)
end
end
while true do
wait(.01)
script.Idle.PlaybackSpeed = (script.Parent.Parent.AxleRR.AssemblyAngularVelocity.Magnitude / (script.Vars.Gears.Base.Value + script.Vars.Gears.AddedPG.Value * script.Vars.Gears.Value)) * 1.25 + 1
end
This is probably a horrible script but I’ll optimize and make it readable once the car works properly. If you need any more information, let me know. Thank you!