Given starting Transform and target position, how to find full 360° angle to the target?

I have a GameObject, and a target’s position (in world coordinates). I want to find the “full” 360° angle to the target (such that “left” gives 90 degrees, “right” gives 270, etc.).

Example: my script is running on a sailing ship, and, given the coordinates of another ship, I want to find the angle to the other ship, starting at my ship’s bow and rotating counter-clockwise.

This has been answered piecemeal in other questions, but I wanted to put it all in one place, with a single, fully-functioning code example in the answer.

Given a transform and a target position, you can use the following code to get the “bearing” of your target. The function is also overloaded so you can just provide two GameObjects.

// Takes a starting object and a target object, and returns the angle to the target 0-359°
function GetBearing(startingObject : GameObject, targetObject : GameObject) : float {
	// Call the "real" GetBearing, passing it our object's transform, and the target's position
	return GetBearing(startingObject.transform, targetObject.transform.position);
}

// Takes a starting object's Transform, and a target object's position, and returns the angle to the target 0-359°
function GetBearing(startingObjectTransform : Transform, targetPosition : Vector3) : float {
	// First, create a Vector3 that is "pointing" from our startingObject to our target.
	var vectorToTarget : Vector3 = targetPosition - startingObjectTransform.position;
	
	// Now, discover the angle between our forward "heading", and the vector we just created.
	// This only gives a result between 0-180, however... we don't know if the target is to our left or right!
	var angleToTarget : float = Vector3.Angle(startingObjectTransform.forward, vectorToTarget);
	
	// AngleDir returns exactly 1 if the target is to the "right" of our forward "heading"
	var directionResult = AngleDir(startingObjectTransform.forward, vectorToTarget, startingObjectTransform.up);
	
	// Based on directionResult, decide if angleToTarget was an angle on the "left" or "right" side of our object.
	if (directionResult == 1) {
		return 360 - angleToTarget;
	} else {
		return angleToTarget;
	}
}

// Given a "forward" heading, a target direction, and an "up" direction, decide if the targetDirection is to our left, right, or front/back.
function AngleDir(forwardVector : Vector3, targetDirection : Vector3, upVector : Vector3) : int {
    var perpendicular : Vector3 = Vector3.Cross(forwardVector, targetDirection);
    var direction : float = Vector3.Dot(perpendicular, upVector);

    if (direction > 0.0) {
        return 1;
    } else if (direction < 0.0) {
        return -1;
    } else {
        return 0;
    }
}

Use like so:

var firingShip : GameObject;
var targetShip : Vector3;
var bearing : float;

// bearing will contain the 360° angle to the targetShip
bearing = GetBearing(firingShip.transform, targetShip);

OR like:

var firingShip : GameObject;
var targetShip : GameObject;
var bearing : float;

// bearing will contain the 360° angle to the targetShip
bearing = GetBearing(firingShip, targetShip);

C# Version without comments (Courtesy Chronos-L):

float GetBearing( GameObject startingObject, GameObject targetObject ) {
    return GetBearing( startingObject.transform, targetObject.transform.position );
}
 
float GetBearing( Transform startTransform, Vector3 targetPosition ) {
    Vector3 vectorToTarget = targetPosition - startTransform.position;
 
    float angleToTarget = Vector3.Angle( startTransform.forward, vectorToTarget );     
    int direction = AngleDir( startTransform.forward, vectorToTarget, startTransform.up );
 
    return ( direction == 1 )? 360f-angleToTarget: angleToTarget;
}
 
int AngleDir( Vector3 forwardVector, Vector3 targetDirection, Vector3 upVector ) {
    float direction = Vector3.Dot( Vector3.Cross( forwardVector, targetDirection ), upVector );
 
    if( direction > 0f ) {
       return 1;
    }
    else if( direction < 0f ) {
       return -1;
    }
    else {
       return 0;
    }
}

This information was gleaned from the following threads: Angle of object relative to transform of second object - Questions & Answers - Unity Discussions http://forum.unity3d.com/threads/52930-Vector3-Angle()?highlight=AngleDir http://forum.unity3d.com/threads/31420-Left-Right-test-function

C# Version without comment

float GetBearing( GameObject startingObject, GameObject targetObject ) {
	return GetBearing( startingObject.transform, targetObject.transform.position );
}

float GetBearing( Transform startTransform, Vector3 targetPosition ) {
	Vector3 vectorToTarget = targetPosition - startTransform.position;
	
	float angleToTarget = Vector3.Angle( startTransform.forward, vectorToTarget );		
	int direction = AngleDir( startTransform.forward, vectorToTarget, startTransform.up );
	
	return ( direction == 1 )? 360f-angleToTarget: angleToTarget;
}

int AngleDir( Vector3 forwardVector, Vector3 targetDirection, Vector3 upVector ) {
    float direction = Vector3.Dot( Vector3.Cross( forwardVector, targetDirection ), upVector );
	
	if( direction > 0f ) {
		return 1;
	}
	else if( direction < 0f ) {
		return -1;
	}
	else {
		return 0;
	}
}

@TheMaster42 Hi, thank you for sharing this code. I’m currently trying to use it in a 2D project to get the bearing between the player’s submarine and a ship, but I’m not sure how to adapt it to the 2D environment. Is it enough to replace startTransform.forward with startTransform.right or does it involve normalized values and other changes?