1
\$\begingroup\$

I am trying to smoothly transition between running, strafing, and running backwards by calculating the angle between the left thumb stick (move) and the right thumb stick (rotate).

It is my understanding that Vector3.Angle() calculates angles to the left as negative and angles to the right as positive. This doesn't seem to be working for me. I am able to use Vector3.Angle () make my character do the following actions:

if(-25 <= angle <= 25) // then run forward

if(25 < angle < 155) //then strafe left

if(-25 > angle > -155) //then strafe right

if(-155 < angle > 155) //then run backwards

Why is Vector3.Angle() behaving like this?

\$\endgroup\$
  • \$\begingroup\$ Just making sure- are you using if-else or repeatedly just using if statements? \$\endgroup\$ – Eric Aug 26 '16 at 1:30
  • \$\begingroup\$ How do you use the function? We can't help you if you don't show us what you're doing... \$\endgroup\$ – Vaillancourt Aug 26 '16 at 2:43
  • \$\begingroup\$ @Doctor-Win, any comments on my answer? If it was helpful, could you accept it please? \$\endgroup\$ – Gazihan Alankus Aug 29 '16 at 13:26
1
\$\begingroup\$

You understanding of Vector3.Angle() is not correct. It always tries to give a positive angle. Quoting Unity Docs:

The angle returned is always the non reflex angle between the two vectors - ie the smaller of the two possible angles between them and never greater than 180 degrees.

Vector3.Angle() has no concept of "to the right" or "to the left". It can't, anyway, because it would need a reference vector for that. You need a normal vector around which you can calculate this angle if you want to differentiate directions in angles with the sign of the angle. Here are two solutions for you:

If you have game objects that track the directions of the two thumb sticks, and if the y Euler angle of each game object represent the angle of the stick:

Transform stick1Transform;
Transform stick2Transform;

float angle1 = stick1Transform.localEulerAngles.y;
float angle2 = stick2Transform.localEulerAngles.y;

// get them to the same mod 360
while(angle1 - angle2 > 180) angle2 += 360;
while(angle2 - angle1 > 180) angle1 += 360;

// use this as the angle that you mentioned in your question
float angle = angle1 - angle2; 

If you want something more general (your "up" vector may change), this would be another approach. You need to supply the up vector that is perpendicular to the two thumb stick vectors here.

Vector3 normal = Vector3.up; // you supply this. if vectors are in x-z, leave it like this.

// THIS is the formula that gives you angles with signs. 
// Vector3.Angle() can not do that because it does not accept 
// a normal vector around which positive and negative are defined
float angle = Mathf.Atan2(
    Vector3.Dot(Vector3.Cross(stick1Vector, stick2Vector), normal), 
    Vector3.Dot(stick1Vector, stick2Vector)) * Mathf.Rad2Deg;

Hope that helps.

\$\endgroup\$
  • \$\begingroup\$ Btw, if you don't have an up vector that is always perpendicular to the two vectors, let me know. I can supply a modified version of the second approach that can deal with that. \$\endgroup\$ – Gazihan Alankus Aug 26 '16 at 8:06
  • \$\begingroup\$ It is a shame that a basic functionality like this is not provided by Unity. \$\endgroup\$ – S. Tarık Çetin Apr 28 '17 at 8:47

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.