Search code examples
unity-game-enginequaternions

Quaternion LookRotation


I am attempting to follow a few unity3d exmaples on c# scripting for tower defense style games. I need a turret to 'aim' at another gameobject. The examples I find do not seem to account for a origin that is not at 0,0,0. Meaning, when the turret is in a different location, it aims based on a starting point, not its current location.

how it is behaving now: http://screencast.com/t/Vx35LJXRKNUm

In the script I am using, how do I give Quaternion.LookRotation information about the current location of the turret for it to include in it's calculation? script, function CalculateAimPosition, line59 :

using UnityEngine;
using System.Collections;

public class TurretBehavior : MonoBehaviour {

public GameObject projectile;
public GameObject muzzleEffect;

public float reloadTime = 1f;
public float turnSpeed = 5f;
public float firePauseTime = .25f;

public Transform target;
public Transform[] muzzlePositions;
public Transform turretBall;

private float nextFireTime;
private float nextMoveTime;
private Quaternion desiredRotation;
private Vector3 aimPoint;

// Update is called once per frame
void Update () 
{
    if (target) 
    {
        if (Time.time >= nextMoveTime) 
        {
            CalculateAimPosition(target.position);
            transform.rotation = Quaternion.Lerp(turretBall.rotation, desiredRotation, Time.deltaTime * turnSpeed);     
        }   

        if (Time.time >= nextFireTime) {
            FireProjectile();
        }
    }
}

void OnTriggerEnter(Collider other)
{
    if (other.gameObject.tag == "TurretEnemy") 
    {
        nextFireTime = Time.time +(reloadTime *.5f);
        target = other.gameObject.transform;
            }

}

void OnTriggerExit(Collider other)
{
    if (other.gameObject.transform == target) {
        target = null;
            }
}

void CalculateAimPosition(Vector3 targetPosition)
{
    aimPoint = new Vector3 (targetPosition.x, targetPosition.y, targetPosition.z);
    desiredRotation = Quaternion.LookRotation (aimPoint);
}

void FireProjectile()
{
    nextFireTime = Time.time + reloadTime;
    nextMoveTime = Time.time + firePauseTime;

    foreach(Transform transform in muzzlePositions)
    {
        Instantiate(projectile, transform.position, transform.rotation);
    }
}
}

Solution

  • The error is in the usage of Quaternion.LookRotation.

    The function takes two Vector3 as input which are a forward direction in world space (and an optional up vector - default Vector3.up), and returns a Quaternion representing the orientation of such a reference frame.

    You are instead supply a world space position as input (targetPosition), which makes no sense. Accidentally a normalized position vector expressed in world space is the direction from origin to the given point, so it works correctly when the tower is placed on the origin.

    What you need to use as LookRotation parameter is the world space direction from the tower to the target:

    Vector3 aimDir = (targetPosition - transform.position).normalized;
    desiredRotation = Quaternion.LookRotation (aimDir );