Good Afternoon, I’m trying to implement a field of view cone for my enemy where if the player enters this cone the enemy will chase them. I have worked out the logic for the enemy regarding the player detection. Now I need to visualise the cone in the gameview to show the user the area they will be spotted. An important feature of this cone is that it wont pass through objects with the layer tag “obstacle” this way the player has hiding spots.
The Image below demonstates how I have used raycasts to show the side boundaries of the view cone and also to the vertices of the object from the enemy (this probably isn’t ideal since my object might have many vertices and at the moment I need to input the vertex positions manually in the inspector which is tedious). I believe all I need to do is “fill in” the gaps between the raycasts but im unsure how easy this is to do.
Here is the mentioned image (The “G” shape is an obstacle):
And here is the code I have so far:
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemyFOV : MonoBehaviour
{
[SerializeField] private List<Vector3> obstacleVertices; // a list of all the obstabcle vertices in the level
[SerializeField] private List<Vector3> obstacleVerticesInRange = new List<Vector3>(); // a list of the obstacle vertices that will be within the enemy's FOV
[SerializeField] private float enemyViewDistance; // the max distance the enemy can see
[SerializeField] [Range(0, Mathf.PI)] private float enemyViewAngle; // the angle above and below the horizontal axis the enemy can see
[SerializeField] private LayerMask hitLayers; // the layers the enemy can't see through
[SerializeField] private RaycastHit2D boundLineTop; // the top bounding line of the cone
[SerializeField] private RaycastHit2D boundLineBottom; // the bottom bounding line of the cone
// Update is called once per frame
void Update()
{
bool movingRight = GetComponent<EnemyMovement>().movingRight; // get which way the enemy is facing so we know where to search for obstacle vertices
int sign = 0;
// get a list off all the obstical vertices in the enemy's FOV
obstacleVerticesInRange = new List<Vector3>(); // clear the list of vertices in range
for (int vertexIndex = 0; vertexIndex < obstacleVertices.Count; vertexIndex++) // for each element of the list
{
// find the angle between the two positions
Vector2 direction = new Vector2(obstacleVertices[vertexIndex].x - transform.position.x, obstacleVertices[vertexIndex].y - transform.position.y);
if (obstacleVertices[vertexIndex].y > transform.position.y)
{
sign = 1;
}
else
{
sign = -1;
}
float angle = Vector2.Angle(Vector2.right, direction) * sign * (Mathf.PI / 180);
if (Vector3.Distance(obstacleVertices[vertexIndex], transform.position) <= enemyViewDistance && ((movingRight && Mathf.Abs(angle) <= enemyViewAngle) || (!movingRight && Mathf.Abs(Mathf.PI - angle) <= enemyViewAngle)))
{
obstacleVerticesInRange.Add(obstacleVertices[vertexIndex]); // add the object to the List
// Send a raycast from the enemy to the vertex
Vector3 origin = transform.position;
RaycastHit2D sightLine = Physics2D.Raycast(origin, direction, enemyViewDistance, hitLayers); // creates a raycast from the enemy in the direction of the obstacle vertex colliding only with the listed layers
//TODO chuck out a ray at the angles of view of enemy
// simulate the raycast (for demonstration purposes)
if (sightLine.collider) // if the ray has hit an obsticle
{
UnityEngine.Debug.DrawLine(new Vector2(transform.position.x, transform.position.y), sightLine.point, Color.red); // if a collider is hit draw from enemy to collision point
}
else
{
UnityEngine.Debug.DrawLine(new Vector2(transform.position.x, transform.position.y), new Vector2(transform.position.x, transform.position.y) + direction * enemyViewDistance, Color.white);
}
}
// also send the rays of the sides of the FOV cone
Vector2 pointOnTopLine;
Vector2 pointOnBottomLine;
if (movingRight)
{
pointOnTopLine.x = enemyViewDistance * Mathf.Cos(enemyViewAngle) + transform.position.x;
pointOnTopLine.y = enemyViewDistance * Mathf.Sin(enemyViewAngle) + transform.position.y;
pointOnBottomLine.x = enemyViewDistance * Mathf.Cos(enemyViewAngle) + transform.position.x;
pointOnBottomLine.y = enemyViewDistance * -Mathf.Sin(enemyViewAngle) + transform.position.y;
}
else
{
pointOnTopLine.x = enemyViewDistance * Mathf.Cos(Mathf.PI - enemyViewAngle) + transform.position.x;
pointOnTopLine.y = enemyViewDistance * Mathf.Sin(Mathf.PI - enemyViewAngle) + transform.position.y;
pointOnBottomLine.x = enemyViewDistance * Mathf.Cos(Mathf.PI - enemyViewAngle) + transform.position.x;
pointOnBottomLine.y = enemyViewDistance * -Mathf.Sin(Mathf.PI - enemyViewAngle) + transform.position.y;
}
// visualise the boundaries
UnityEngine.Debug.DrawLine(new Vector2(transform.position.x, transform.position.y), pointOnTopLine, Color.yellow);
UnityEngine.Debug.DrawLine(new Vector2(transform.position.x, transform.position.y), pointOnBottomLine, Color.yellow);
}
}
}
I should mention I’m new to Unity and coding so thank you for your patience!