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:
However, graphics hardware can't really draw perfect circles. You're always going to end up with a polygon 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.
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:
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_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:
And when I add a dotted line to connect the two half-circles, it's starting to look like a cone!
Here, we have two radii:
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_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:
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:
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++)
sphere_curr.x = cos(degrees_to_radians(angle_curr));
sphere_curr.y = sin(degrees_to_radians(angle_curr));
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 (
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.