Thursday, September 9, 2010

Rotating your Character in Unity3D

To keep up with my “starting simple Unity3D series”, I want to share a code snipped on how you can rotate your characters or objects by code in a Unity3D game or application.
This method is one of the most common things you will need to do, specially if you are programming your NPCs. The code is my own version of many approaches I have seen on the tutorials and forums, and I believe is quite standard. 
The reason I wanted to post it here is because I added a lot of comments and some official documentation. Hopefully if will help you to understand better the mechanics of movement in the 3D space, and as a plus is already in C#, which lacks some visibility in the tutorials and forum answers.

// Rotates the character (Y axis only) to face the given position 
void RotateTowards(Vector3 position)
{
    // Get the direction between the given 
    // position and the current character's position
    Vector3 direction = position - transform.position;
  
    // Get rid of the Y axis variations
    direction.y = 0.0f;
   
    // Check if the character's rotation is 
    // already facing the given position. Include a little damping.
    if (direction.magnitude < 0.1f)
    {
        return;
    }
  
    // If not, it means we have to rotate the character 
    // over its Y axis to face the given position
    // To rotate our character, we need to use a smooth transition
    // between the current rotation and the target rotation


    // Use Quaternion.Slerp() to smoothly rotate the character.
    // Transform.rotation: The rotation of the transform 
    // in world space stored as a Quaternion.
    // Quaternion: Quaternions are used to represent rotations.
    // Quaternion: They are compact, don't suffer from gimbal 
    // lock and can easily be interpolated. 
    // Quaternion: Unity internally uses Quaternions to 
    // represent all rotations.
    // Quaternion.Slerp: Interpolates rotation between 
    // the rotations of from and to.
    // Quaternion.Slerp: Choose from and to not to be the 
    // same as the object you attach this script to.
    // Quaternion.LookRotation: Creates a rotation that 
    // looks along forward with the the head upwards along upwards
    // Quaternion.LookRotation: Logs an error if the forward 
    // direction is zero
    
    // Also we will use the character's rotation speed 
    // to ratate the character smoothly over time
    // We multiply the rotation speed by the Time.deltaTime 
    // to make the rotation by seconds, and not by frames
    transform.rotation = Quaternion.Slerp(transform.rotation,
            Quaternion.LookRotation(direction), 
            rotateSpeed * Time.deltaTime);
  
    // Now we need to get rid of the rotations on the X
    // and Z axis, because the character should only be able
    // to rotate over its Y axis. To do this we need to modify 
    // the transform's Euler Angles


    // Transform.eulerAngles: The rotation as Euler angles in 
    // degrees.
    // Transform.eulerAngles: The x, y, and z angles 
    // represent a rotation z degrees around the z axis, 
    // Transform.eulerAngles: x degrees around the x axis, 
    // and y degrees around the y axis (in that order).
    // Transform.eulerAngles: Only use this variable to read 
    // and set the angles to absolute values. 
    // Transform.eulerAngles: Don't increment them, 
    // as it will fail when the angle exceeds 360 degrees. 
    // Transform.eulerAngles: Use Transform.Rotate instead
    
    transform.eulerAngles = new Vector3(0, 
                                    transform.eulerAngles.y, 0); 
}
Cheers!
-arbbot

5 comments:

  1. Hi, nice article!

    Only one question: what parameter should be passed to the RotateTowards() funciont when it gets called into the Update()?

    I'm trying with the character's transform.position, but I'm getting weird results...

    ReplyDelete
  2. Hi Axe, thanks for the comment. You should pass the target position, since you want your character to face that target, right? Let's say you have the reference to the taget's transform, so you should pass the targetTransform.position parameter. Let me know how it goes !

    Cheers!
    -arbbot

    ReplyDelete
  3. Hey! Really great post, just what I needed.

    Right now I'm implementing your method, but need it to rotate on the Z-axis instead of the Y-axis. So these are the lines that I changed:

    direction.z = 0.0f;
    transform.eulerAngles = new Vector3(0, 0, transform.eulerAngles.z);

    Is that all? Because I've tried your code and works perfectly, but after I make those changes it doesn't rotate at all.

    ReplyDelete
  4. Hey! Really great post, just what I needed.

    Right now I'm implementing your method, but need it to rotate on the Z-axis instead of the Y-axis. So these are the lines that I changed:

    direction.z = 0.0f;
    transform.eulerAngles = new Vector3(0, 0, transform.eulerAngles.z);

    Is that all? Because I've tried your code and works perfectly, but after I make those changes it doesn't rotate at all.

    ReplyDelete
  5. Hi Anthony.
    Can you give me document or link for learn quaternion deep
    Thanks

    ReplyDelete