- Home /
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.
Answer by robertbu · Jan 21, 2013 at 04:12 PM
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);
}
}
Hi!
Is it work with Oculus Rift (0.7SD$$anonymous$$)?
Thank you very much!
While using this I've noticed that some things are wrong. Atan2 takes y,x as parameters. The Sin/Cos calls hence need to be switched and I've simply scaled the coordinates with Screen.width and height (ViewportToWorldPoint didn't work properly). Also I've used an UI/Image on a canvas since the plane looked weird. The clip plane things are not necessary then.
I cannot tell you how many hours I have been working on this same problem. Your solution is the only one on the Internet that worked for me. Thank you so much, I wish I could send you a 50.
Answer by bernardfrancois · Jan 20, 2013 at 10:11 PM
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).
Answer by adam_melhem · Feb 11, 2013 at 10:50 PM
they told me to stick the 2d flat arow to cam . and you may use the help of SmoothLockAt
Answer by gamezuv · Apr 19, 2015 at 02:29 PM
using System.Collections; public class ArrowTest : MonoBehaviour {Blockquoteusing UnityEngine;
public GameObject goTarget; private SpriteRenderer srenderer; private Transform myTranform; void Start() { myTranform = transform; srenderer = GetComponent(); } 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
Your answer

Follow this Question
Related Questions
how to find direction between two points 2 Answers
Make a pointer arrow that shows where player will go 1 Answer
ScreenToGUIPoint 1 Answer
Preventing "LookAt" from flipping? 1 Answer
Local Direction of Vector3 1 Answer