- Home /
Make UI compass point to 3D object
I want a compass needle to point to a target object offscreen. The compass is an upwards-facing arrow sprite in a Canvas, so will rotate on the Z-axis. The rest of the game is 3D.
From other answers here on UA I've made this calculation:
var dir : Vector3;
var angle : float;
var arrow: GameObject;
dir = target.transform.position - transform.position;
angle = Mathf.Atan2(dir.x, dir.z);
arrow.transform.eulerAngles = Vector3(0, 0, angle);
...but this doesn't give the correct angle. Could anyone give me a pointer please?
@scribe of course, I've missed out an important part! $$anonymous$$ake this into an answer and I'll accept it!
Answer by Scribe · Aug 31, 2015 at 06:16 PM
Mathf.Atan2(dir.x, dir.z) returns the rotation in Radians, so you have to multiply it by the conveniently named 'Mathf.Rad2Deg'
angle = Mathf.Atan2(dir.x, dir.z)*Mathf.Rad2Deg;
This worked for me:
var targetPosLocal = Camera.transform.InverseTransformPoint(targetObjectPosition);
var targetAngle = -$$anonymous$$athf.Atan2(targetPosLocal.x, targetPosLocal.y) * $$anonymous$$athf.Rad2Deg - 90;
ArrowUIObject.eulerAngles = new Vector3(0, 0, targetAngle);
Answer by SuperJaques · Sep 01, 2015 at 01:30 PM
Put this script to arrow object and drop your target to "toFollow" public variable or ref it some other way.
using UnityEngine; using System.Collections;
public class Follow : MonoBehaviour {
public GameObject toFollow;
void Update () {
Vector3 v = toFollow.transform.position;
//z is meaningless
v.z = 0;
//arrow always looks forward so it will show correctly to viewer, and world-up changes the rotation
transform.LookAt(transform.position+transform.forward,v-transform.position);
} }
I have a compass needle sprite pointing upward, parented to a UI canvas that is set to Screen Space Camera. So, wherever the canvas/camera goes the sprite goes along for the ride and keeps it's relative position. I have been searching for hours for some sort of LookAt2D equivalent. I tried the above code and it works famously! I up voted this answer. Here is the code from @SuperJaques in a bit more readable format.
public class CompassPointer : $$anonymous$$onoBehaviour
{
public GameObject toFollow;
void Update()
{
Vector3 v = toFollow.transform.position;
//z is meaningless
v.z = 0;
//arrow always looks forward so it will show correctly to viewer, and world-up changes the rotation
transform.LookAt(transform.position + transform.forward, v - transform.position);
}
}
Answer by fermmmm · Sep 07, 2017 at 09:37 PM
This worked for me:
var targetPosLocal = Camera.transform.InverseTransformPoint(targetObjectPosition);
var targetAngle = -Mathf.Atan2(targetPosLocal.x, targetPosLocal.y) * Mathf.Rad2Deg - 90;
ArrowUIObject.eulerAngles = new Vector3(0, 0, targetAngle);
This is amazing, finally works without any issues. To anyone reading this, be sure to change that -90 in "Mathf.Rad2Deg - 90;" to your specific rotation required by sprite.
Answer by mBakr · Dec 08, 2017 at 04:31 AM
Yet another solution:
Vector3 dir = transform.InverseTransformDirection(target.position - transform.position);
float angle = Mathf.Atan2(-dir.x, dir.z) * Mathf.Rad2Deg;
uiTrans.eulerAngles = new Vector3(0, 0, angle);