2
\$\begingroup\$

I have a rigidbody and use 4 keys to addtorque in 4 different directions:

  • W adds torque positively along the X axis (pitch forward)
  • S adds torque negatively along the X axis (pitch backward)
  • A adds torque negatively along the Y axis (yaw left)
  • D adds torque postively along the Y axis (yaw right)

enter image description here

The rigidbody is able to rotate around/spin in any combination of these directions, but my issue is how can I count the number of rotations it has done in any given axis? Eg. if the player has completed 2 360 rotations to their left I would like to display "2 Left Spins" etc.

I have tried storing the eulerangles of each axis but this is no good as it resets after certain degrees.

I think the way it could work is on keydown reset a degrees counter, while the key is being held I could continue to store the change in rotation for that axis, and then on keyup I could divide this total number of degrees by 360. I'm not sure how to do this in C# though, or if this is the best way to do this.

How could I do this?

\$\endgroup\$
2
\$\begingroup\$

Might be advantageous to not demand a totally full circle (= airplane back completely horizontal rotation) for an "accepted roll" - maybe it's sufficient, and more user-friendly, to reach an almost horizontal position in order to consider it a completed roll? In addition, it's always a bit hairy to use an accumulation over a long period of time - it may diverge. I talk about roll below, but one can ofc do it for any axis. I didn't bother with gimbal lock issues.

  1. Grab the Euler angle each frame, change it to -180 ... 180 degree domain using

    if (angle > 180) {
        angle -= 360;
        }
    
  2. If abs(angle) passes a threshold, say 40 degrees (can be any between 1 and 179), resolve a value to be -1 if the rotation was clockwise, 1 if it was counterclockwise, add that to A (that was originally 0):

    if   ( (abs(angle) > 40) AND (abs(prevangle) <= 40) ) 
    orif ( (abs(angle) < 40) AND (abs(prevangle) >= 40) ) {
        A += sign(angle - prevangle); // sign() should return 1, 0 or -1
        }
    
  3. Check if abs(A) has reached 2:

    if (abs(A) = 2) {
        [Add one to number of rolls (can even count left and right rolls separately, based on sign of A]
        A = 0; // Reset A
        }
    
  4. Always store angle for next frame:

    prevangle = angle;
    

That is: Passing the threshold in either direction adds 1 or -1 to A. Passing again in the same direction adds again 1 or -1 to A. If A reaches 2 or -2, a roll was made.

Aborting the roll before the 2nd "add" just causes A to become 0 again.

| improve this answer | |
\$\endgroup\$
3
\$\begingroup\$

Get the difference between the last and the current EulerAngles variable, add it to another variable, check that variable and if the variable is over 360, subtract 360 from it and add one to the spin counter.

So, something like this (might not work exactly as it's typed in, didn't test the code but it can at least be used as pseudo-code):

float rollDegree = 0, previousRollAngle;
int leftSpins = 0, rightSpins = 0;

void Start(){ previousRollAngle = gameObject.transform.eulerAngles.x;}
void Update(){
    if(rollDegree >= 360)
    {
        rollDegree = rollDegree - 360;
        leftSpins++;
    }
    else if (rollDegree <= -360)
    {
        rollDegree = rollDegree + 360;
        rightSpins++;
    }
    rollDegree = rollDegree + (gameObject.transform.eulerAngles.x - previousRollAngle);
    previousRollAngle = gameObject.transform.eulerAngles.x;
}
| improve this answer | |
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.