Menu
CoddyTech

Quaternions

Part of the Physics and Gameplay section of Coddy's Unity journey. Lesson 43 of 71.

A Quaternion is Unity's type for a rotation: transform.rotation is one, and so is what Quaternion.Euler returns. Its four numbers x, y, z and w are not angles, and you never need to set them yourself. What you do with rotations is multiply. A rotation times a vector turns the vector:

Vector3 a = Quaternion.Euler(0, 90, 0) * Vector3.forward;       // (1, 0, 0)
Vector3 b = Quaternion.Euler(0, 0, 45) * new Vector3(2, 0, 0);  // (1.41, 1.41, 0)
Vector3 lamp = transform.position + transform.rotation * new Vector3(0, 1, 2);

The rotation goes on the left: Vector3.forward * transform.rotation does not compile. The third line turns an offset by the object's own rotation, so lamp is the point 1 unit above and 2 in front of the object in its own directions, whichever way it faces.

A rotation times a rotation combines the two turns. transform.rotation * Quaternion.Euler(0, 90, 0) is the object's rotation followed by a quarter turn around its own y axis; with the order swapped, the quarter turn is around the world's y axis. For an upright object both give the same result. For a plane banked 30 degrees they do not, because its own y axis leans with it:

Quaternion banked = Quaternion.Euler(0, 0, 30);
Quaternion own = banked * Quaternion.Euler(0, 90, 0);    // nose (0.87, 0.5, 0): it climbs as it turns
Quaternion world = Quaternion.Euler(0, 90, 0) * banked;  // nose (1, 0, 0): it stays level

Quaternion.identity is no turn at all, the one you have passed to Instantiate. Multiplying by it changes nothing, and transform.rotation = Quaternion.identity; puts an object back to its unturned pose.

challenge icon

Challenge

Medium

Make Space fire a spread of three bullets that turns with the gun.

  1. Replace the Instantiate line with for (int i = -1; i <= 1; i++).
  2. In it, set Quaternion aim = transform.rotation * Quaternion.Euler(0, i * spread, 0);.
  3. Spawn each bullet 1 unit out along its direction: Instantiate(bulletPrefab, transform.position + aim * Vector3.forward, aim);.

Press Play, turn and fire: three bullets fan out, 20 degrees apart. Then Check.

Try it yourself

using UnityEngine;

public class Gun : MonoBehaviour
{
    public GameObject bulletPrefab;
    public float turnSpeed = 90f;
    public float spread = 20f;

    void Update()
    {
        if (Input.GetKey(KeyCode.RightArrow)) transform.Rotate(0, turnSpeed * Time.deltaTime, 0);
        if (Input.GetKey(KeyCode.LeftArrow)) transform.Rotate(0, -turnSpeed * Time.deltaTime, 0);

        if (Input.GetKeyDown(KeyCode.Space))
        {
            // One bullet, straight ahead. Fire three: -spread, 0 and spread degrees.
            Instantiate(bulletPrefab, transform.position, transform.rotation);
        }
    }
}

All lessons in Physics and Gameplay

Practice on your own: Unity playground