# Math on Orientation (Car wheels)

I’m currently working on a custom car chassis, and I need the wheels to rotate.
I’m using TweenService and Orientation(vector3) to rotate them with the Steer inputs, so it becomes something like “Steer * self.Engine.Orientation”, it works fine but the problem is, that when the multiplying makes it go past 180 degrees, instead of of making it go at -180, it goes at 190; making the wheels go crazy and spin

Heres a vid showing when I drive the car at the 180 world space orientation, the wheels spins

This might just be super easy to solve lol but I have tried other methods to making the wheels move like CFrame, but it dosen’t work unless I anchor the Wheels

Have you tried to check if the degree (do not rotate before checking) is greater than `180` and set it to `-180`?

why would I check that? the math on the equation for the wheels rotating dosent understand the maximum is 180 world space rotation and it has to switch over to -180 to perform,

the code for the tween performance goes like:
(self.Engine.Orientation + vector3.new(0,Steer * 20,0))

Yes so why don’t you limit it I don’t get it?

like math.clamp? it wont work because it gets stuck there until the car orientation switches over to -180 from 180, the steer can be ahead like for example 200 if the car orientation is 180, beause of the equation

I did make a car chassis before (actually, several of them), and had success with something similar to this. What I did is I modified the CFrame of the weld from the base to the wheel in object space. I never used TweenService to modify the CFrame.

Note that using TweenService for something physics-related isn’t something you would want to do. You also always only want to use CFrames when working with physics.

To fix the current issue at hand, simply try subtracting the new wheel’s orientation from 360. You should then get a number between -180 and 180

For example:

``````local CurrentWheelOrientation = 200
local NewWheelOrientation = (CurrentWheelOrientation - 360) -- returns -160
``````

Also, if the orientation is going over 360 then you should use the modulo/modulus operator.

``````local CurrentWheelOrientation = 560
local NewWheelOrientation = (CurrentWheelOrientation % 360) - 360 -- Should return -160
``````

how else can I make the wheels rotate smooth cuz I wanna use CFrame

how did you make the wheel rotate smoothly? if you did that

Well, for steering I did weld.C0 = weld.C0:Lerp(targetCFrame, 0.1)
and it looped on Heartbeat in a LocalScript. I made a Script that did the same thing on the server, but didn’t run on Heartbeat and did not lerp.

k so the targetcframe is like CFrame.new() * CFrame.Angles(0,self.SteerRate,0)?

Well, the best way to do this would be to use an AlignOrientation.

I did use AlignOrientation but I think it made the whole car rotate when it was standing still

No way! I just used some plain welds welded to the base. You can look at my inventory of models I made a few of them public (except this car chassis is not public).

so just cframe:lerp() then? but dosent it a require a “acceleration” that goes 0 to 1? in the last argument on the cframe lerp function?

Set the acceleration to 0.1. If you constantly lerp something 10% closer to its goal, it will travel there exponentially. It’s just an alternative I use to TweenService’s Exponential EasingStyle. If you want it to go into a certain position, you must use `FuzzyEq` and a Vector3, although I don’t think this is necessary as you can always question the CFrame target value.

How about these ToObjectSpace(), ToWorldSpace() functions, idk, just make it cframe and then ToOrientation() to make it vector3 orientation?

because the equation goes that the orientation must be relative to the car and then it adds on the steer input

I wouldn’t do either of those, but you can keep your existing code and use ToObjectSpace(), because Welds use object space.

Basically, I used math.rad and a certain angle of CFrame to get steering to work, but I forgot which direction it was in. The CFrame handled both the suspension and steering, and the suspension was handled in world space and the steering in object space.

I have also suspension,

btw here is my code to the suspension applying

`v.Steer.C0 = v.CFrame:Inverse() * (v.CFrame + v.CFrame:vectorToWorldSpace(Vector3.new(0, -Hit.Distance + self.WheelRadius, 0)))`

I can add `* CFrame.Angles(0,Steer,0)` add on but I gotta fix the lerping stuff first…

Wait a second! I posted something wrong!

So, I did put the suspension in object space, I had a dedicated WheelScript that had a value called currentDistance that was constantly fed information by the main script, which handled the suspension and everything.

So, don’t use ToWorldSpace or ToObjectSpace. It should be in object space to begin with. Also, you don’t need to add a Vector3 into a CFrame. Just use the 3 arguments of the CFrame.new(x, y, z) function.

The lerping stuff is simple. Make an empty CFrame that is just a local variable, and change that as needed. Then, add a loop that will change the CFrame of the weld all the time (or when it is changed), which will lerp the Weld’s CFrame to the target CFrame.

Other than that, I think you got it! I hope the project comes together nice and smooth.

1 Like