3
\$\begingroup\$

I'm facing a problem with a game I'm making. Currently I can select an enemy and mark it as shown on the image: enter image description here

But now I want to show the position of the selected enemy on the screen when it's off camera. So my questions are:

  1. How do I know when an enemy is off camera.

  2. How can I show in GUI an arrow on the edge of the screen that points to the position of that enemy. Perhaps something related to what I did to point towards the crosshair?

Vector3 positionOnScreen = Camera.main.ScreenToWorldPoint(mousePos + Vector3.forward * range);
Vector3 targetDir = positionOnScreen - transform.position;

Thanks!

\$\endgroup\$
  • \$\begingroup\$ do you need location Indicator? \$\endgroup\$ – Seyed Morteza Kamali Oct 17 at 14:34
  • \$\begingroup\$ Yes, thank you, this was what I needed for the second question! \$\endgroup\$ – Hector Oct 18 at 11:03
3
\$\begingroup\$
  1. You can easily know if a world point is visible by a given camera using Camera.WorldToViewportPoint. This will return a Vector2 that represents the position of your object in the viewport. A viewport goes from [0,0] (bottom left) to [1,1] (top right). If the returned value has a component lower than 0 or higher than 1 it means that the object is offscreen (or partially offscreen).

  2. As Seyed Morteza Kamali suggested in his comment, you can point the position of your object using basic intersection


About the second point the solution is all about linear function (y = ax + b).

            Vector2 a = viewport_pos; // viewport position of your offscreen item
            Vector2 b = target_viewport_pos; // viewport position of the target (in your case 0.5;0.5 for the 

            if (b.x == a.x || a.y == b.y) return;

            // y = px + d
            float p = (b.y - a.y) / (b.x - a.x);
            float d = a.y - p * a.x;

            float new_vy;
            float new_vx;

            // Check the axis with the biggest difference to define on which side of the screen you should display the arrow.
            float diff_x = a.x - b.x;
            float diff_y = a.y - b.y;

            // Display the arrow on the left/right sides
            if (diff_x > diff_y)
            {
                new_vx = viewport_pos.x < 0 ? 0f : 1f;
                new_vy = new_vx * p + d;
            }
            else // Display the arrow on the top/down sides
            {
                new_vy = viewport_pos.y < 0 ? 0f : 1f;
                new_vx = (new_vy - d) / p;
            }

            // This is the position of your arrow.
            Vector3 new_pos = Camera.main.ViewportToWorldPoint(new Vector3(new_vx, new_vy));
```
\$\endgroup\$
  • \$\begingroup\$ Can you add the information from the link in your point 2 to your answer in case the link breaks? We generally try to answer questions in our answers themselves and not just link to external websites which might provide an answer for a while and then disappear or change their URLs. \$\endgroup\$ – Philipp Oct 17 at 15:58
  • 1
    \$\begingroup\$ Hey @Philipp sure, I'll do that asap. \$\endgroup\$ – lvictorino Oct 17 at 17:16
  • \$\begingroup\$ Thanks, very well explained. The only remaining question that I have is that, since in the last line of the code says that the Arrow has a World position, would that also apply to a GUI element? Because I want the arrow to be part of the GUI. \$\endgroup\$ – Hector Oct 18 at 11:10
  • \$\begingroup\$ Then just use ViewportToScreenPoint instead of ViewportToWorldPoint ;) \$\endgroup\$ – lvictorino Oct 18 at 11:35
  • \$\begingroup\$ I've tried using new_pos = mainCamera.ViewportToScreenPoint(new Vector3(new_vx, new_vy)); but something is not right, because sometimes the x value of this position is negative. \$\endgroup\$ – Hector Oct 18 at 17:47

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.