├── FieldOfViewEditor.cs ├── README.md └── FieldOfView.cs /FieldOfViewEditor.cs: -------------------------------------------------------------------------------- 1 | using UnityEditor; 2 | using UnityEngine; 3 | 4 | [CustomEditor(typeof(FieldOfView))] 5 | public class FieldOfViewEditor : Editor 6 | { 7 | private void OnSceneGUI() 8 | { 9 | FieldOfView fov = (FieldOfView)target; 10 | Handles.color = Color.white; 11 | Handles.DrawWireArc(fov.transform.position, Vector3.up, Vector3.forward, 360, fov.radius); 12 | 13 | Vector3 viewAngle01 = DirectionFromAngle(fov.transform.eulerAngles.y, -fov.angle / 2); 14 | Vector3 viewAngle02 = DirectionFromAngle(fov.transform.eulerAngles.y, fov.angle / 2); 15 | 16 | Handles.color = Color.yellow; 17 | Handles.DrawLine(fov.transform.position, fov.transform.position + viewAngle01 * fov.radius); 18 | Handles.DrawLine(fov.transform.position, fov.transform.position + viewAngle02 * fov.radius); 19 | 20 | if (fov.canSeePlayer) 21 | { 22 | Handles.color = Color.green; 23 | Handles.DrawLine(fov.transform.position, fov.playerRef.transform.position); 24 | } 25 | } 26 | 27 | private Vector3 DirectionFromAngle(float eulerY, float angleInDegrees) 28 | { 29 | angleInDegrees += eulerY; 30 | 31 | return new Vector3(Mathf.Sin(angleInDegrees * Mathf.Deg2Rad), 0, Mathf.Cos(angleInDegrees * Mathf.Deg2Rad)); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # FieldOfView 2 | A simple Field of View system for the Unity Engine with target detection and obstacle blocking 3 | 4 | # How To Use 5 | - Import both scripts into your project 6 | 7 | - Ensure FieldOfViewEditor is inside of the Editor folder inside of Unity or else your build will fail to compile! 8 | 9 | - Set up two new Layers, one for your Target objects and one for your Obstacle objects 10 | 11 | ![New Layers](https://i.imgur.com/4H19Eg4.png) 12 | 13 | - Set your player (target) to be on the Target layer 14 | 15 | - Set any obstacles that block the enemies field of view to be on the Obstacle layer 16 | 17 | ![Field Of View Inspector](https://i.imgur.com/PW20aYg.png) 18 | 19 | - Attach the FieldOfView script to your Enemy 20 | 21 | - Configure the view radius and angle properties to your liking 22 | 23 | ![Field Of View Inspector](https://i.imgur.com/q0Ovpzw.png) 24 | 25 | - Set the target layer mask to be your Target layer 26 | 27 | - Set the obscruction layer mask to be your Obstacle layer 28 | 29 | 30 | ## FAQ 31 | 32 | **Why isnt my raycast detecting the player / obstacles?** 33 | Check your objects have colliders, Raycasts need to hit colliders to work 34 | Check your objects are assigned to the correct layers 35 | Check your FieldOfView script is looking at the right layers in the inspector 36 | 37 | **Why is my build failing with these scripts?** 38 | FieldOfViewEditor needs to be inside a folder called Editor 39 | -------------------------------------------------------------------------------- /FieldOfView.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using UnityEngine; 5 | 6 | public class FieldOfView : MonoBehaviour 7 | { 8 | public float radius; 9 | [Range(0,360)] 10 | public float angle; 11 | 12 | public GameObject playerRef; 13 | 14 | public LayerMask targetMask; 15 | public LayerMask obstructionMask; 16 | 17 | public bool canSeePlayer; 18 | 19 | private void Start() 20 | { 21 | playerRef = GameObject.FindGameObjectWithTag("Player"); 22 | StartCoroutine(FOVRoutine()); 23 | } 24 | 25 | private IEnumerator FOVRoutine() 26 | { 27 | WaitForSeconds wait = new WaitForSeconds(0.2f); 28 | 29 | while (true) 30 | { 31 | yield return wait; 32 | FieldOfViewCheck(); 33 | } 34 | } 35 | 36 | private void FieldOfViewCheck() 37 | { 38 | Collider[] rangeChecks = Physics.OverlapSphere(transform.position, radius, targetMask); 39 | 40 | if (rangeChecks.Length != 0) 41 | { 42 | Transform target = rangeChecks[0].transform; 43 | Vector3 directionToTarget = (target.position - transform.position).normalized; 44 | 45 | if (Vector3.Angle(transform.forward, directionToTarget) < angle / 2) 46 | { 47 | float distanceToTarget = Vector3.Distance(transform.position, target.position); 48 | 49 | if (!Physics.Raycast(transform.position, directionToTarget, distanceToTarget, obstructionMask)) 50 | canSeePlayer = true; 51 | else 52 | canSeePlayer = false; 53 | } 54 | else 55 | canSeePlayer = false; 56 | } 57 | else if (canSeePlayer) 58 | canSeePlayer = false; 59 | } 60 | } 61 | --------------------------------------------------------------------------------