Geographical bearing of an object

A ship sails at night in a harbour, following a leading sector light. On a bearing between 200 and 190 degrees, the light is seen red, between 190 and 170, white and between 170 and 160, green.

I need to know when making the light red, white or green. As I used to work with Flash ActionScript, I would calculate the arc tangent of the difference between the X coordinates and the Y (or rather, Z for Unity3D). But, somehow I feel that I just need to call a Unity3D function but I don’t know which one. I tried:

var angle = Vector3.Angle(lighthouse.transform.position, ship.transform.position);

and I get something but not the actual angles from 160 to 200. I have looked at many answers on this forum but they all seem to address the relative difference of heading between two objects. I only need to know the bearing from the object as a global value since z positive is the north, for me.

Thanks in advance,


First, Vector3.Angle produces then unsigned angle between two vectors using all x,y, and z of the two vectors. Second, you are calculating that position, not relative to the ship, but relative to the origin. You have a few choices. You can use Mathf.Atan2() to calculate an absolute angle on the plane relative to the ship. Assuming you are on the XZ palne, something like:

var v3 = lighthouse.transform.position - ship.transform.position;
angle = Mathf.Atan2(v3.z, v3.x) * Mathf.Rad2Deg;  

This will produce an absolute angle where Vector3.right is be 0 and increase counter-clockwise. You can use Mathf.DeltaAngle() to calculate angle differences.

If you don’t need the angle, but are just interested in whether the point is to the left or right of you, there are easier choices. Take a look at SignedDotProduct in the Math3D script in the Wiki.

Another solution by @Eric5h5 can be found here.

Just to build off of @robertbu code, here’s what I did:

Vector3 targetDirection = (target.transform.position - source.transform.position);
float angleToTarget = (Mathf.Atan2(targetDirection.z, targetDirection.x) * Mathf.Rad2Deg) - 90f;
float heading = angleToTarget;
if (angleToTarget >= -90f && angleToTarget < 0f)
	// North-East
	Debug.Log("NE:" + angleToTarget);
	heading = heading * -1f;
else if (angleToTarget >= -180f && angleToTarget < -90f)
	// South-East
	Debug.Log("SE:" + angleToTarget);
	heading = heading * -1f;
else if (angleToTarget >= -270f&& angleToTarget < -180f)
	// South-West
	Debug.Log("SW:" + angleToTarget);
	heading = heading * -1f;
else if (angleToTarget >= 0f && angleToTarget < 90f)
	// North-West
	Debug.Log("NW:" + angleToTarget);
	heading = (heading - 360f) * -1f;