# Question How would you go on about making a Physics based Steering Wheel?

Discussion in 'Scripting' started by SKULLgaming8777, Sep 9, 2023.

1. ### SKULLgaming8777

Joined:
Dec 11, 2021
Posts:
15
By physics based i mean that the steering wheel is a rigidbody attached by a rotational hinge. This is because its for a VR game. Im trying to make a steering wheel that is able to turn more than 180 degrees because all solutions ive found just allowed me to move the wheel about 180 degrees before it breaks.

2. ### Kurt-Dekker

Joined:
Mar 16, 2013
Posts:
37,210
Sounds like they're using .eulerAngles.

Don't use .eulerAngles.

Track your own notion of how much the steering is rotated and then drive the rotation explicitly according to whatever ratio you want the steering wheel to drive the wheel angle.

All about Euler angles and rotations, by StarManta:

https://starmanta.gitbooks.io/unitytipsredux/content/second-question.html

Last edited: Sep 9, 2023
PraetorBlue likes this.
3. ### SKULLgaming8777

Joined:
Dec 11, 2021
Posts:
15
What would be the best way to notion my own steering wheel value?
The way i tried it is by subtracting the x rotation by an older frames x rotation and then constantly adding the frame's result to a variable. I feel like this "should" work but i think by the way quaternions are set up it doesnt.

4. ### Kurt-Dekker

Joined:
Mar 16, 2013
Posts:
37,210
Attached is a simple "dial with your finger" demo.

Around about line 56 is where it rotates the transform by angleDelta.

Modify the above to keep your own float steer angle and update it by angleDelta.

Code (csharp):
1. private float mySteerDirection;
like so:

Code (csharp):
1. mySteerDirection += angleDelta;
and use mySteerDirection however you want to turn your wheel collider or your hinge, probably by scaling it way down, perhaps dividing it by 10 or something.

File size:
20.1 KB
Views:
15
5. ### SKULLgaming8777

Joined:
Dec 11, 2021
Posts:
15
i cant express how thankfull i am for this help, but what i was needing help with is getting the rotational value in sort of a specific way, since the rotation itself is already gonna be handeled by the rigidbody and the players hand i only need the rotation in such way where when i for example turn the wheel 360 degrees to the right it would return 360 and if i spin it once more to the right its gonna return 720, third one would be 1080 and it would just keep going like that. when you would start turning left again and lets say you do a whole 360 degree turn, the value would now reverse and go back to 720. i hope that makes sense and i apologize for not explaining correctly.

6. ### Kurt-Dekker

Joined:
Mar 16, 2013
Posts:
37,210
I'm sorry, the assertion I made above was incorrect. The number does not fully accumulate.

See several posts below (presently Post #16) for a true RevolutionCounter script. Nothing else in this post is guaranteed.

DISREGARD THE BELOW!!

I fixed it so that it accumulates forever as you turn the dial. Here it is in action.

Use the above package I posted, but replace the script with this:

(changes have been flagged with
``// related to degree accumulation``
)

Code (csharp):
1. using System.Collections;
2. using System.Collections.Generic;
3. using UnityEngine;
4.
5. // by @kurtdekker
6. // simple example of rotating something like a dial on a safe
7. //
8. // EDIT: this has been tweaked to sum and report total degrees turned.
9. //
10.
11. public class RotateZViaDrag : MonoBehaviour
12. {
13.     public bool RotateAroundAxis;
14.
15.     Vector3 lastPosition;
16.
17.     // related to degree accumulation
18.     private float mySteerDirection;
19.     public UnityEngine.UI.Text DegreeOutput;
20.
21.     void OnMouseDown()
22.     {
23.         lastPosition = Input.mousePosition;
24.     }
25.
26.     void PerformLinearRotation()
27.     {
28.         Vector3 currPosition = Input.mousePosition;
29.
30.         Vector3 difference = currPosition - lastPosition;
31.
32.         lastPosition = currPosition;
33.
34.         // now choose what axis to care about... this adds X and Y
35.         float change = difference.x + difference.y;
36.
37.         // and it rotates it around the Z (forward)
38.         transform.Rotate(new Vector3(0, 0, change));
39.     }
40.
41.     void PerformCircularRotation()
42.     {
43.         // where is our center on screen?
44.         Vector3 center = Camera.main.WorldToScreenPoint(transform.position);
45.
46.         // angle to previous finger
47.         float anglePrevious = Mathf.Atan2(center.x - lastPosition.x, lastPosition.y - center.y);
48.
49.         // related to degree accumulation
50.         Vector2 arm1 = new Vector2(center.x - lastPosition.x, lastPosition.y - center.y);
51.
52.         Vector3 currPosition = Input.mousePosition;
53.
54.         // angle in radians to current finger
55.         float angleNow = Mathf.Atan2(center.x - currPosition.x, currPosition.y - center.y);
56.
57.         // related to degree accumulation
58.         Vector2 arm2 = new Vector2(center.x - currPosition.x, currPosition.y - center.y);
59.
60.         lastPosition = currPosition;
61.
62.         // how different are those angles?
63.         float angleDelta = angleNow - anglePrevious;
64.
65.         // scale up to degrees (everything above is in radians!)
67.
68.         // related to degree accumulation
69.         // compare the arms and accumulate distance
70.         float steerDelta = Mathf.Asin( Vector3.Cross( arm1.normalized, arm2.normalized).z) * Mathf.Rad2Deg;
71.         mySteerDirection += steerDelta;
72.         Debug.Log( ((int)mySteerDirection).ToString());
73.         if (DegreeOutput) DegreeOutput.text = ((int)mySteerDirection).ToString();
74.
75.         // rotate by that much
76.         transform.Rotate(new Vector3(0, 0, angleDelta));
77.     }
78.
79.     void OnMouseDrag()
80.     {
81.         if (RotateAroundAxis)
82.         {
83.             PerformCircularRotation();
84.         }
85.         else
86.         {
87.             PerformLinearRotation();
88.         }
89.     }
90. }
Where the mouse input happens (the position and previous position that feed into
``arm1``
and
``arm2``
vectors) can be replaced with just any arbitrary Transform parented below your steering wheel.

NOTE: this works as rotations around the Z+ axis.

Last edited: Sep 10, 2023
7. ### SKULLgaming8777

Joined:
Dec 11, 2021
Posts:
15
Thank you so much! The accumulation is exactly what i needed, but how would i convert this to 3D? My steering wheel does not use player inputs like the mouse since its a vr game. it uses hands that will rotate the wheel. So the whole Rotating part i already got settled. I only need this accumilation mechanism that tracks how much the wheel rotated and if possible would this also work for the X Axis?

8. ### Kurt-Dekker

Joined:
Mar 16, 2013
Posts:
37,210
See several posts below (presently Post #16) for a true RevolutionCounter script. Nothing else in this post is guaranteed.

I think my original statement might have been a bit strong.

Nothing about the computation on line 70 is tied to any axis.

It does however presume that the axis of the wheel is not changing over its course. That would introduce error.

The dependence on +Z axis is simply from the creation of arm1 and arm2, which are x/y Vector2s.

I suspect it would work fine in another orientation as long as you were consistently tracking a rotating part of the wheel.

Last edited: Sep 10, 2023
9. ### SKULLgaming8777

Joined:
Dec 11, 2021
Posts:
15
what about the script should i exactly be changing to make it work with my case? For reference my wheel is a child of a pirate ship model. it has a hingejoint component to attach it to the ship and a rigidbody. I want to know what I can change, remove, not remove, etc

10. ### Kurt-Dekker

Joined:
Mar 16, 2013
Posts:
37,210
See several posts below (presently Post #16) for a true RevolutionCounter script. Nothing else in this post is guaranteed.

Instead of computing arm1 / arm2 the way I did above, compute it as the Vector difference between the center (hub) and a single fixed point on the wheel. Doesn't matter where the point is, it just can't be at the center.

The code above will observe that point's rotation in the same way that it observes the mouse motion above.

Last edited: Sep 10, 2023
11. ### SKULLgaming8777

Joined:
Dec 11, 2021
Posts:
15
Could you please give me an example?

12. ### Kurt-Dekker

Joined:
Mar 16, 2013
Posts:
37,210
See several posts below (presently Post #16) for a true RevolutionCounter script. Nothing else in this post is guaranteed.

I've told you everything. Get the vector from the hub of your wheel and a point on the wheel (this frame and last) and feed that into the computations at line 70 above. That's it, honest.

Last edited: Sep 10, 2023
13. ### SKULLgaming8777

Joined:
Dec 11, 2021
Posts:
15
Thank you very much for the help I appreciate it. I'll give it a try

14. ### Kurt-Dekker

Joined:
Mar 16, 2013
Posts:
37,210
See several posts below (presently Post #16) for a true RevolutionCounter script. Nothing else in this post is guaranteed.

I tried to replicate this based on what I told you above and there is still one assumption of +Z in line 70: the use of the .z component of the computed cross product.

I'm sorry but I don't have time to dig further into it right now. I suggest perhaps using the Transform of your actual steering wheel to compute the inverse position of an observed point so that once it feeds into the arm1 / arm2 calculation, it is normalized to the global +Z axis.

Last edited: Sep 10, 2023
15. ### SKULLgaming8777

Joined:
Dec 11, 2021
Posts:
15
No problem man. Thank you for the help.

16. ### Kurt-Dekker

Joined:
Mar 16, 2013
Posts:
37,210
Heh, you're very welcome... I think I was getting tangled up in my "Rotate Z" demo code.

It was bugging me so much I pushed into it and solved it.

This is WAY simplified: just place this script on a Transform anywhere in any orientation.

It will read out the accumulated degrees rotated around the Transform's local +Z

You just get a reference to this script and read it out of the
``TotalDegrees``
field.