It sets the attachment orientation via scripting. I’ve found that to be way better. The video shows how to smooth it out so it doesn’t jerk the wheels around when you steer.
That’s actually something I thought you might be doing, but didn’t mention in the post.
It’s effectively the same as using angular limits on a CylindricalConstraint. Works just as well, I definitely approve. For me, a property I can easily reset to 0 is easier to work with than an attachment that I modify.
Do you do it linearly, exponentially, or do you do it fancily and use a P(I)D controller? :3
I think my standard chassis system does it exponentially, but also allows you to specify a point for the wheels to target. See:
It’s something like… every frame it gets x percent closer to reaching its target. Or the error gets x percent smaller. I don’t remember.
In your BoundingBoxTouched
function, you’re parenting the wrong script:
Client.Parent = GetPlayer.Backpack
You should parent the OccupiedClientScript
instead:
OccupiedClientScript.Parent = GetPlayer.Backpack
Does anyone have a tutorial on ackerman steering? i have not found any
This is what I’ve used for mine:
I wrote down my math/code for it a while back:
off topic but can you do a tutorial on how you made your plane that you posted on twitter/youtube
Maybe later in the future. I’m using that for an actual game so it contains some trade secrets
A little off topic, but what makes ackerman steering better than “Same Angle Steering”?
With “Same Angle Steering”
See how one of the wheels is kind of misaligned? That wheel causes friction and skidding.
Ackermann:
The difference is subtle but it works, I assure you.
and now to work out how to apply that ackerman code into mine
I may have broken the car…
local Car = script:WaitForChild("Car").Value
local StopValue = script:WaitForChild("Stop")
local SteeringAngle = script:WaitForChild("SteeringAngle")
local Player = game.Players.LocalPlayer
local Seat = Car.Body.VehicleSeat
local FL = Car.Chassis.Platform.AttachmentFL
local FR = Car.Chassis.Platform.AttachmentFR
local CFFL = Car.Chassis.Platform.CylindricalConstraintFL
local CFFR = Car.Chassis.Platform.CylindricalConstraintFR
local CFRL = Car.Chassis.Platform.CylindricalConstraintRL
local CFRR = Car.Chassis.Platform.CylindricalConstraintRR
local Steer = 0
local Throttle = 0
local heartbeat
local function Update(dt)
-- Steer:
local Goal = Seat.SteerFloat * SteeringAngle.Value
Steer = Steer + (Goal - Steer) * math.min(dt * Seat.TurnSpeed, 1)
FL.Orientation = Vector3.new(0, -Steer, -90)
FR.Orientation = Vector3.new(0, -Steer, -90)
-- Throttle:
local ThrottleGoal = Seat.ThrottleFloat
Throttle = Throttle + (ThrottleGoal - Throttle) * math.min(dt * Seat.TurnSpeed, 1)
local Torque = Seat.Torque
local Speed = Seat.MaxSpeed * Throttle
CFFL.MotorMaxTorque = Torque
CFFR.MotorMaxTorque = Torque
CFRL.MotorMaxTorque = Torque
CFRR.MotorMaxTorque = Torque
CFFL.AngularVelocity = Speed
CFFR.AngularVelocity = -Speed
CFRL.AngularVelocity = Speed
CFRR.AngularVelocity = -Speed
Player.Character.Humanoid.JumpPower = 0
end
local function Start()
print("Start Client")
heartbeat = game:GetService("RunService").Heartbeat:Connect(Update)
end
local function Stop()
print("Stop Client")
heartbeat:Disconnect()
wait(1)
Player.Character.Humanoid.JumpPower = 50
script:Destroy()
end
Start()
if (StopValue.Value) then Stop() return end
StopValue.Changed:Connect(function(ShouldStop)
if (not ShouldStop) then return end
Stop()
end)
game:GetService("UserInputService").InputBegan:Connect(function(Input)
if (Input.KeyCode == Enum.KeyCode.F) then
Player.Character.Humanoid.Jump = true
Player.Character.HumanoidRootPart.CFrame = Car.TpPart.CFrame
end
end)
edit: nvm i am dumb
Great tutorial, loved the way you navigated and explained everything and why it was in great detail. I do want to point out there is a large difference with cylinder vs sphere wheels. Sphere wheels have by far better collision that cylindrical ones, even more noticeable when turning.
(The gifs might not show it all but in-game its its 100% visible)
Here is the car I rigged with the tutorial using cylindrical wheel collision:
Notice how when turning the wheels ‘phase’ and jump through the road when turning, and (not shown) when going at high speeds the wheels suffer from this as it gets more intense.
Heres the rig using spheres as wheel collision:
Every turn now is silky smooth, no visible phasing as with cylindrical collisions. At high speeds it remains this smooth with no issues!
Now I do want to point out when changing to sphere collisions you loose the ability to grind into into walls as the sphere would collide with it before the cars body did, I guess a simple way to fix this would be to set it different collision in collisions group.
image|481x393
Either way, great tutorial. Hope to see more tutorials like this! (Was wondering how to do car gear calculations )
There is a good topic on this:
Thats how I do my gears, and rpm’s and stuff ^
That looks great, I am doing something like that of my own: https://i.imgur.com/M6Ehzpm.png
Using a car that is close to my heart. It was my first car that i worked on with my dad
Out of curiosity, does anybody know what causes this / why it happens? I’ve always wanted to know.
I think the reason is due to lateral forces. On cylinders, there’s a hard edge. On actual tires, you don’t have a hard edge (wheels are rubbery and slightly rounded on the edges). Using a sphere simulates this a little better. This is just my assumption. I don’t actually know.
Am I going mad?
Because car is a value??
The “Car” object there is an ObjectValue in the script that points back to the actual Car model. This is needed because the script lives in the player’s backpack, so it doesn’t know which car model to use otherwise. Thus, we grab the value of that ObjectValue right away.
The Stop object is a BoolValue, but we don’t want to grab the value of it. We want the actual object because we will use it to listen for changes to the value.
Crazyman32 released a block of code that had the logic for ackerman steering, I thought it may be a good idea to incorporate that into the code he wrote for this tutorial. Anyways, here it is. Hope you find it useful.
local function Update(dt)
-- Steer:
local goal = -seat.SteerFloat * maxSteerAngle
steer = steer + (goal - steer) * math.min(dt * seat.TurnSpeed, .5)
local radians = math.rad(90 - math.abs(steer))
local h =(attFR.WorldPosition - attRR.WorldPosition).Magnitude
local z = (attRR.WorldPosition - attRL.WorldPosition).Magnitude
local x = math.tan(radians) * h
local y = (x + z)
local outerTurnAngle = 90 - math.deg(math.atan2(y, h))
if (steer > 0) then
attFL.Orientation = Vector3.new(0, steer, -90)
attFR.Orientation = Vector3.new(0, outerTurnAngle, -90)
else
-- Right
outerTurnAngle = -outerTurnAngle
attFL.Orientation = Vector3.new(0, outerTurnAngle, -90)
attFR.Orientation = Vector3.new(0, steer, -90)
end
-- Throttle:
local throttleGoal = seat.ThrottleFloat
throttle = throttle + (throttleGoal - throttle) * math.min(dt * seat.TurnSpeed, 1)
local torque = seat.Torque
local speed = seat.MaxSpeed * throttle
cylFL.MotorMaxTorque = torque
cylFR.MotorMaxTorque = torque
cylRL.MotorMaxTorque = torque
cylRR.MotorMaxTorque = torque
cylFL.AngularVelocity = speed
cylFR.AngularVelocity = -speed
cylFL.AngularVelocity = speed
cylRR.AngularVelocity = -speed
end