How To Make A 2D GUI Arrow Point At A 3D Object

Im making a fighter jet game and have got to a problem about how to make a GUI 2D arrow position itself on my screen to point towards the enemy jet (3D Object). What i really want is just a 2D arrow that moves around the screen pointing towards a 3D Object, but so far have had no luck.

This is the sort of thing i wan’t to achieve.

I’m assuming that you want the arrows to show only when a target is not visible and the target is in front of the camera. Make a plane with an arrow texture. The code is cleanest if the arrow points up with rotation (0,0,0) and the tip is at the anchor (0,0,0). This can be done using the build-in plane and an empty game object or using the CreatePlane editor script. Place the plane at the near clippling plane of the camera and size to taste.

Use WorldToViewportPoint() to translate a targets position to viewport coordinates. If the x and y values are between 0 and 1, the target’s center point is visible. If the value of z is positive, then the targt is in front of the camera. From this you can devise a test so to show and hide the arrow. You may want to widen the parameters so the arrow does not show for targets that are nearly past your position and nearly in view. This will mitigate partially show targets having an arrow.

Below is a bit of starter code. Note I place the arrow on an ellipse touching the sides of the viewport. I leave placing the arrow on the edges of the viewport to you.

using UnityEngine;
using System.Collections;

public class ArrowTest : MonoBehaviour {
	
	public GameObject goTarget;

	void Update () {
		PositionArrow();		
	}
	
	void PositionArrow()
	{
		renderer.enabled = false;
		
		Vector3 v3Pos = Camera.main.WorldToViewportPoint(goTarget.transform.position);
		
		if (v3Pos.z < Camera.main.nearClipPlane)
			return;  // Object is behind the camera
		
		if (v3Pos.x >= 0.0f && v3Pos.x <= 1.0f && v3Pos.y >= 0.0f && v3Pos.y <= 1.0f)
			return; // Object center is visible
				
		renderer.enabled = true;
		v3Pos.x -= 0.5f;  // Translate to use center of viewport
		v3Pos.y -= 0.5f; 
		v3Pos.z = 0;      // I think I can do this rather than do a 
		                  //   a full projection onto the plane
		
		float fAngle = Mathf.Atan2 (v3Pos.x, v3Pos.y);
		transform.localEulerAngles = new Vector3(0.0f, 0.0f, -fAngle * Mathf.Rad2Deg);
		
		v3Pos.x = 0.5f * Mathf.Sin (fAngle) + 0.5f;  // Place on ellipse touching 
		v3Pos.y = 0.5f * Mathf.Cos (fAngle) + 0.5f;  //   side of viewport
		v3Pos.z = Camera.main.nearClipPlane + 0.01f;  // Looking from neg to pos Z;
		transform.position = Camera.main.ViewportToWorldPoint(v3Pos);
	}
}

I suggest converting the other plane’s positions to the camera’s coordinate space.
This can be done by multiplying these positions with the Camera’s worldToLocalMatrix.

After that, you could determine the angles from these positions (using Vector3.Angle, passing a vector like Vector3.up or Vector3.right - depending on which direction the arrow points within their image file).

they told me to stick the 2d flat arow to cam . and you may use the help of SmoothLockAt

Blockquoteusing UnityEngine;
using System.Collections;

public class ArrowTest : MonoBehaviour {

public GameObject goTarget;
private SpriteRenderer srenderer;
private Transform myTranform;

void Start()
{
	myTranform = transform;
	srenderer = GetComponent<SpriteRenderer>();
}
void LateUpdate () {
	PositionArrow();        
}

void PositionArrow()
{
	srenderer.enabled = false;
	if(goTarget){
	if(goTarget.activeSelf){
	Vector3 v3Pos = Camera.main.WorldToViewportPoint(goTarget.transform.position);
	
	if (v3Pos.z < Camera.main.nearClipPlane)
		return;  // Object is behind the camera
	
	if (v3Pos.x >= 0.0f && v3Pos.x <= 1.0f && v3Pos.y >= 0.0f && v3Pos.y <= 1.0f)
		return; // Object center is visible
	
		srenderer.enabled = true;
	v3Pos.x -= 0.5f;  // Translate to use center of viewport
	v3Pos.y -= 0.5f; 
	v3Pos.z = 0;      // I think I can do this rather than do a 
	//   a full projection onto the plane
	
	float fAngle = Mathf.Atan2 (v3Pos.x, v3Pos.y);
	myTranform.eulerAngles = new Vector3(0.0f, 0.0f, -fAngle * Mathf.Rad2Deg);
	
	v3Pos.x = 0.5f * Mathf.Sin (fAngle) + 0.5f;  // Place on ellipse touching 
	v3Pos.y = 0.5f * Mathf.Cos (fAngle) + 0.5f;  //   side of viewport
	v3Pos.z = Camera.main.nearClipPlane + 1f;  // Looking from neg to pos Z;
	myTranform.position = Camera.main.ViewportToWorldPoint(v3Pos);
	}
	}
	else
	{
		srenderer.enabled = false;
	}
}

}

Blockquote