0
\$\begingroup\$

I currently have a scene where 3d a gents move throughout a grid, each time they move that can pick a random cardinal direction up,down,left or right. They then rotate to face that direction using Quaternion.Slerp. However I noticed there were some edge cases where the agents didn't move at all, and found out the problem was being caused during rotations at 180 degrees. Doing some reading on this I found that Slerp and Lerp dont handle rotations at this degree very well if at all and now I'm at a loss on how to proceed. I tried using transform.rotateAround() to rotate the character around the Y axis to the direction, but again at 180 degrees the agents start to just spin in circles forever.

Here's my current rotate code:

IEnumerator rotate(){      
        while(Quaternion.Angle(transform.rotation,direction) > 0.3){
            var tempRotation = Quaternion.Slerp(transform.rotation, direction, Time.deltaTime * rotateSpeed);
            this.transform.rotation = tempRotation;
            yield return null;
        }
        this.transform.rotation = direction;
    }

Heres the code that handles picking where to go:

int choice = Random.Range(0,4);
        prevPos = pos;
        if((choice == 0) && pos.x < gs.maxX){
            pos.x += 1;
            direction = Quaternion.AngleAxis(-90,Vector3.up);
            }
            else if((choice == 1) && pos.x > 0){
            pos.x -= 1;
            direction = Quaternion.AngleAxis(90,Vector3.up);
            }
            else if((choice == 2)&& pos.y < gs.maxY){
            pos.y += 1;
            direction = Quaternion.AngleAxis(180,Vector3.up);
            }else if((choice == 3) && pos.y > 0){
            pos.y -= 1;
            direction = Quaternion.AngleAxis(0,Vector3.up);
        }

If someone could point me in the right direction on how to handle this gracefully I'd really appreciate it!

\$\endgroup\$
5
  • 1
    \$\begingroup\$ Have you considered using Quaternion.RotateTowards instead? \$\endgroup\$ – DMGregory Apr 24 '20 at 15:18
  • \$\begingroup\$ It seems to work! but its a lot slower in its step compared to the other functions do you know why? or why this one differs from the other functions? \$\endgroup\$ – Jamie Hyland Apr 24 '20 at 15:36
  • \$\begingroup\$ It gives you a speed parameter that you can adjust until it's as fast as you want it to be. \$\endgroup\$ – DMGregory Apr 24 '20 at 15:37
  • \$\begingroup\$ I know so do Slerp and Lerp im using Time.DeltaTime*rotationspeed and they havent changed but the rotations take a lot longer using lookToward \$\endgroup\$ – Jamie Hyland Apr 24 '20 at 15:38
  • 1
    \$\begingroup\$ No, Lerp and Slerp do not expose a speed, they expose a blend ratio, so 1.0 = jump all the way to the end, 0.0 = stay all the way at beginning, 0.5 = jump halfway in a single leap. (And the deltaTime adjustment you're using there is incorrect for this type of blend) RotateTowards takes a parameter in degrees like the documentation says, so 0.5 means rotate half a degree. \$\endgroup\$ – DMGregory Apr 24 '20 at 15:40
1
\$\begingroup\$

Using Quaternion.RotateTowards() fixed my issue. Here's the new code:

IEnumerator rotate(){      
        while(Quaternion.Angle(transform.rotation,direction) > 0.3){
            transform.rotation = Quaternion.RotateTowards(transform.rotation,direction,rotateSpeed*Time.deltaTime);
            yield return null;
        }
        this.transform.rotation = direction;
    }

Turns out upon further testing, this does not work. I have tried to modify it so that it will rotate around the Y axis in increments until the angle between agentPosition and the new destination is less than 180 degrees:

 IEnumerator rotate(){    
          angle = Quaternion.Angle(transform.rotation,direction);
            while(angle > 0.3){
                if(angle >= 180){
                    //There's problem with Slerp at angles >= 180 degrees so manually
                    // rotate around Y axis until Slerp can be used
                    transform.RotateAround(transform.position,Vector3.up,15*Time.deltaTime*rotateSpeed);
                    angle = Quaternion.Angle(transform.rotation,direction);
                }else{
                    transform.rotation = Quaternion.RotateTowards(transform.rotation,direction,Time.deltaTime*(rotateSpeed*90));
                }
                angle = Quaternion.Angle(transform.rotation,direction);
                yield return null;
            }
        this.transform.rotation = direction;
    }

This however still does not work.

\$\endgroup\$
0

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.