Offscreen Target Indicator

Updated 5 days ago in [A] Unity Scripting
Share on Facebook0Tweet about this on TwitterShare on Google+0Share on Reddit0
5 on March 12, 2018

Hello !

I wanted to know that how can I create an Offscreen Target Indicator in Unity 3D ?

All of the videos and forums that I searched , hadn’t made things clear .

Thanks so much .

  • Liked by
  • Mouledoux
4 on March 14, 2018

Sorry it took so long, but some of this was new grounds for me.

Anyway here is a link to the script on GitHub, I’ll paste it below too.


The problem is something is off the screen, and we want to know where it is off the screen. That’s a 3 part problem that Unity has some builtin solutions for.

1st: where is it in the scene? That’s just the GameObject’s transform.position, easy enough.

2nd: where is it on the screen? You could do this manually, and get the relative distance and position from the camera and convert that into a 2D vector with relation to the camera’s view angle, but Unity has a handy function called WorldToViewportPoint, which takes in a Vector3, and gives us a convenient Vector2 between 0,0 (bottom left) to 1,1 (top right)

3rd: where is it on the UI? Now you could actually get this directly from the the world position, but that causes issues when the object is behind you and the numbers are a bit harder to work with. So instead, if we take that Vector2 we just made, and pass it into ViewportToScreenPoint, this will give us, in pixels, a point on the canvas that is the same as the point on the screen.


That’s all 3 problems solved, so now lets draw an icon on the screen.

Well, not quite, I lied, it’s actually a 4 part problem, but the 4th can’t all be done with builtin functions. See, so far we’ve only been working in the viewport (whats on the screen right now), but we want to track stuff NOT in the viewport with stuff that IS in the viewport (the icon that will be at the edge). Without going too much into detail, all you really need to do is clamp the values to the icon doesn’t go off the screen, and maybe a few extra things in the event the object is directly behind you.


So that’s it. Here’s the script like I said. It’s not perfect and really only has a few functions at the moment, but hopefully this is enough to get you going and adding your own things to it. All you need to do to use this, is to drop the script on whatever object you want to track, give it an icon to display, and make sure you have a canvas in your scene. It will add the icon to the scene at runtime, you do not need to set a reference in the inspector.

using UnityEngine;
using UnityEngine.UI;
public class TargetIndicator : MonoBehaviour
    private Camera mainCamera;
    private RectTransform m_icon;
    private Image m_iconImage;
    private Canvas mainCanvas;
    private Vector3 m_cameraOffsetUp;
    private Vector3 m_cameraOffsetRight;
    private Vector3 m_cameraOffsetForward;
    public Sprite m_targetIconOnScreen;
    public Sprite m_targetIconOffScreen;
    [Range(0, 100)]
    public float m_edgeBuffer;
    public Vector3 m_targetIconScale;
    public bool ShowDebugLines;
    void Start ()
       mainCamera = Camera.main;
       mainCanvas = FindObjectOfType<Canvas>();
       Debug.Assert((mainCanvas != null), "There needs to be a Canvas object in the scene for the OTI to display");
       void Update ()
      private void InstainateTargetIcon()
          m_icon = new GameObject().AddComponent<RectTransform>();
          m_icon.localScale = m_targetIconScale; = name + ": OTI icon";
         m_iconImage = m_icon.gameObject.AddComponent<Image>();
          m_iconImage.sprite = m_targetIconOnScreen;
       private void UpdateTargetIconPosition()
          Vector3 newPos = transform.position;
          newPos = mainCamera.WorldToViewportPoint(newPos);
          if(newPos.z < 0)
                newPos.x = 1f - newPos.x;
                newPos.y = 1f - newPos.y;
                newPos.z = 0;
               newPos = Vector3Maxamize(newPos);
        newPos = mainCamera.ViewportToScreenPoint(newPos);
       newPos.x = Mathf.Clamp(newPos.x, m_edgeBuffer, Screen.width - m_edgeBuffer);
        newPos.y = Mathf.Clamp(newPos.y, m_edgeBuffer, Screen.height - m_edgeBuffer);
       m_icon.transform.position = newPos;
    public void DrawDebugLines()
       Vector3 directionFromCamera = transform.position - mainCamera.transform.position;
      Vector3 cameraForwad = mainCamera.transform.forward;
       Vector3 cameraRight = mainCamera.transform.right;
       Vector3 cameraUp = mainCamera.transform.up;
      cameraForwad *= Vector3.Dot(cameraForwad, directionFromCamera);
       cameraRight *= Vector3.Dot(cameraRight, directionFromCamera);
       cameraUp *= Vector3.Dot(cameraUp, directionFromCamera);
      Debug.DrawRay(mainCamera.transform.position, directionFromCamera, Color.magenta);
      Vector3 forwardPlaneCenter = mainCamera.transform.position + cameraForwad;
      Debug.DrawLine(mainCamera.transform.position, forwardPlaneCenter,;
       Debug.DrawLine(forwardPlaneCenter, forwardPlaneCenter + cameraUp,;
       Debug.DrawLine(forwardPlaneCenter, forwardPlaneCenter + cameraRight,;
       public Vector3 Vector3Maxamize(Vector3 vector)
       Vector3 returnVector = vector;
       float max = 0;
       max = vector.x > max ? vector.x : max;
       max = vector.y > max ? vector.y : max;
       max = vector.z > max ? vector.z : max;
       returnVector /= max;
       return returnVector;
5 days ago


I don’t know how to thank you .

I’m going to paste this code into unity in order to see whether it works or not .


Thank you so much .


5 days ago

Hello again .

I pasted your code . It works perfectly fine but , you haven’t still wrote the part that when the target goes offscreen , the icon of the target would change .


Thanks .

5 days ago

Correct. There is a place for the off screen icon, but I never added in any functionality to it. You could add it in pretty easy though.


Because WorldToViewportPoint gives us a 2d vector no larger than 1, 1 (at least, never when it’s on the screen, but we don’t care about that), and when it’s behind us we use Maximize to force at least the X or Y to be 1. That means that whenever it’s off the screen or behind us, the magnitude of newPos (after the if statement) will be larger than 1.


If you just throw in a check like that AFTER the if statement that’s already in there, you could just swap the icon there.


5 days ago

Thank you very much .

Show more replies
  • Liked by