Tell me more ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

My goal is to draw a dynamic indicator for a cube, which represents the field of view. The ideal indicator would look the same as in Metal Gear Solid(the blue ones):

enter image description here

From what I have gathered, I need an angle and a length for the indicator as such for a 50° FoV: enter image description here

Now my issue is what method should I use to draw the indicator? A procedural mesh or is there a less demanding way of doing this?

share|improve this question

1 Answer

up vote 9 down vote accepted

I can't give you a Unity-specific answer (sorry!), but I can tell how I would solve this. I would generate a bunch of points on a circle using the blue vector.

First, what is a circle? Well, a circle looks like this:

Circle

However, graphics hardware can't really draw perfect circles. You're always going to end up with a polygon approximation:

Approximation

We do this approximation by using sine and cosine functions. If you remember from trigonometry, a circle is 360 degrees or 2 pi. Sine and cosine functions take a value out of 2 pi and give you a distance either in the x (cosine) or y (sine) axis. A very useful property indeed.

In code:

x = (cos(degrees_to_radians(angle));
y = (sin(degrees_to_radians(angle));

Now, what you want is not a circle, but a half-circle. Specifically, you want this:

Bit of circle

This can be achieved by using an angle_start and an angle_end. We then loop over this using an angle_delta that is calculated by dividing the difference between angle_start and angle_end over the quality we want.

Another useful property of approximating circles with sine and cosine (also known as the "unit circle") is that it can be shrunk or grown using a radius value. So let's add a radius to our pseudo-code:

x = (cos(degrees_to_radians(angle)) * radius;
y = (sin(degrees_to_radians(angle)) * radius;

How can we use this for our field-of-view cone? Well, we can use the same circle but draw it at different distances:

Almost a cone

And when I add a dotted line to connect the two half-circles, it's starting to look like a cone!

Cone!

Here, we have two radii: dist_min and dist_max. Our code becomes:

x_min = (cos(degrees_to_radians(angle)) * dist_min;
y_min = (sin(degrees_to_radians(angle)) * dist_min;

x_max = (cos(degrees_to_radians(angle)) * dist_max;
y_max = (sin(degrees_to_radians(angle)) * dist_max;

However, we also need two angles: one for the current step and one for the next step. We'll call these angle_curr and angle_next. Now our code becomes:

x_curr_min = (cos(degrees_to_radians(angle_curr)) * dist_min;
y_curr_min = (sin(degrees_to_radians(angle_curr)) * dist_min;

x_curr_max = (cos(degrees_to_radians(angle_curr)) * dist_max;
y_curr_max = (sin(degrees_to_radians(angle_curr)) * dist_max;

x_next_min = (cos(degrees_to_radians(angle_next)) * dist_min;
y_next_min = (sin(degrees_to_radians(angle_next)) * dist_min;

x_next_max = (cos(degrees_to_radians(angle_next)) * dist_max;
y_next_max = (sin(degrees_to_radians(angle_next)) * dist_max;

Now we have four points on our half-circles. Let's store these points as triangles. Here's a diagram that should help clear up how can make triangles out of these four points:

Triangles yo

So, what do we need to do draw a cone?

  • Determine the start angle and the end angle. This is done using the enemy's direction and field of view variable.
  • Determine the quality of our approximation. 15 steps should be good enough for most purposes.
  • Loop over the difference between start and end using the delta ((end - start) / quality).
  • Convert our angles to four points.
  • Convert the four points to two triangles.

When we combine these steps, here's what we will end up with:

Finished product

In full pseudo-code:

int quality = 15;

float dist_min = 0.5f;
float dist_max = 15.f;

vec2 pos = GetEnemyPosition();
float angle_lookat = GetEnemyAngle();
float angle_fov = GetEnemyFieldOfView();

float angle_start = angle_lookat - angle_fov;
float angle_end = angle_lookat + angle_fov;
float angle_delta = (angle_end - angle_start) / quality;

float angle_curr = 0.f;
float angle_next = angle_delta;

for (int i = 0; i < quality - 1; i++)
{
    vec2 sphere_curr;
    sphere_curr.x = cos(degrees_to_radians(angle_curr));
    sphere_curr.y = sin(degrees_to_radians(angle_curr));

    vec2 sphere_next;
    sphere_next.x = cos(degrees_to_radians(angle_next));
    sphere_next.y = sin(degrees_to_radians(angle_next));

    vec2 pos_curr_min = pos + sphere_curr * dist_min;
    vec2 pos_curr_max = pos + sphere_curr * dist_max;

    vec2 pos_next_min = pos + sphere_next * dist_min;
    vec2 pos_next_max = pos + sphere_next * dist_max;

    WriteTriangle(pos_curr_min, pos_curr_max, pos_next_max);
    WriteTriangle(pos_next_max, pos_curr_min, pos_next_min);

    angle_curr += angle_delta;
    angle_next += angle_delta;
}

This should create the cone you want. Try playing with the parameters (dist_min, dist_max and quality) to get the effect you want. It should only be a few triangles per enemy, I don't think it's much of a problem to generate this every frame. Only consider optimizing it when it becomes a problem.

share|improve this answer
I tried to figure out what happens in there, hard without any comments, but apparently your WriteTriangle method draws a procedural mesh according to the angles? – Esa Jun 27 '12 at 7:21
I always try to make code readable without any comments (because comments lie). However, in this case I will have to make an exception. WriteTriangle is a method that takes three vec2's and saves it as a triangle in some kind of mesh structure. Internally, the mesh would store a (dynamic) list of vertices and use that to render a model. – knight666 Jun 27 '12 at 7:47
I have updated my answer (with pictures!) to hopefully clear things up for you. – knight666 Jun 27 '12 at 8:28
+1. Very detailed answer. Just lacks the texturing to get the same look as in the reference image :) – bummzack Jun 27 '12 at 8:50

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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