Part of these game systems:
Enemy Chase AI
Enemy AI that detects the player within radius, chases with line-of-sight, and returns to patrol when player escapes.
How to Use
1
Attach EnemyChaseAI to your enemy
2
Tag your player as 'Player'
3
Set detection radius and field of view
4
Configure chase speed and give-up distance
5
Hook OnPlayerDetected and OnAttackRange events
6
Gizmos show detection/attack ranges in Scene view
7
Pair with WaypointPatrol for idle behavior
Source Code
C#
using UnityEngine;
using UnityEngine.Events;
/// <summary>
/// Enemy AI with detection radius, line-of-sight check,
/// and chase behavior. Returns to origin when player escapes.
/// </summary>
public class EnemyChaseAI : MonoBehaviour
{
[Header("Detection")]
[SerializeField] private float detectionRadius = 10f;
[SerializeField] private float fieldOfView = 120f;
[SerializeField] private bool requireLineOfSight = true;
[SerializeField] private LayerMask obstacleLayers;
[Header("Chase")]
[SerializeField] private float chaseSpeed = 5f;
[SerializeField] private float rotationSpeed = 8f;
[SerializeField] private float giveUpDistance = 15f;
[SerializeField] private float attackRange = 1.5f;
[Header("Target")]
[SerializeField] private string playerTag = "Player";
[Header("Events")]
public UnityEvent OnPlayerDetected;
public UnityEvent OnPlayerLost;
public UnityEvent OnAttackRange;
private Transform player;
private Vector3 originPosition;
private bool isChasing;
private bool isReturning;
public bool IsChasing => isChasing;
private void Start()
{
originPosition = transform.position;
GameObject playerObj = GameObject.FindGameObjectWithTag(playerTag);
if (playerObj != null)
player = playerObj.transform;
}
private void Update()
{
if (player == null) return;
float distToPlayer = Vector3.Distance(transform.position, player.position);
if (isChasing)
{
if (distToPlayer > giveUpDistance)
{
StopChasing();
return;
}
if (distToPlayer <= attackRange)
{
OnAttackRange?.Invoke();
return;
}
ChasePlayer();
}
else if (isReturning)
{
ReturnToOrigin();
}
else
{
if (CanDetectPlayer(distToPlayer))
{
isChasing = true;
OnPlayerDetected?.Invoke();
}
}
}
private bool CanDetectPlayer(float distance)
{
if (distance > detectionRadius) return false;
// FOV check
Vector3 dirToPlayer = (player.position - transform.position).normalized;
float angle = Vector3.Angle(transform.forward, dirToPlayer);
if (angle > fieldOfView * 0.5f) return false;
// Line of sight check
if (requireLineOfSight)
{
if (Physics.Raycast(transform.position + Vector3.up, dirToPlayer, distance, obstacleLayers))
return false;
}
return true;
}
private void ChasePlayer()
{
Vector3 direction = (player.position - transform.position);
direction.y = 0f;
if (direction.magnitude > 0.1f)
{
Vector3 moveDir = direction.normalized;
transform.position += moveDir * chaseSpeed * Time.deltaTime;
Quaternion targetRot = Quaternion.LookRotation(moveDir);
transform.rotation = Quaternion.Slerp(transform.rotation, targetRot, rotationSpeed * Time.deltaTime);
}
}
private void StopChasing()
{
isChasing = false;
isReturning = true;
OnPlayerLost?.Invoke();
}
private void ReturnToOrigin()
{
Vector3 direction = (originPosition - transform.position);
direction.y = 0f;
if (direction.magnitude <= 0.3f)
{
isReturning = false;
return;
}
Vector3 moveDir = direction.normalized;
transform.position += moveDir * (chaseSpeed * 0.6f) * Time.deltaTime;
Quaternion targetRot = Quaternion.LookRotation(moveDir);
transform.rotation = Quaternion.Slerp(transform.rotation, targetRot, rotationSpeed * Time.deltaTime);
}
#if UNITY_EDITOR
private void OnDrawGizmosSelected()
{
Gizmos.color = new Color(1f, 0.3f, 0.3f, 0.3f);
Gizmos.DrawWireSphere(transform.position, detectionRadius);
Gizmos.color = new Color(1f, 0.6f, 0f, 0.3f);
Gizmos.DrawWireSphere(transform.position, giveUpDistance);
Gizmos.color = Color.red;
Gizmos.DrawWireSphere(transform.position, attackRange);
// FOV lines
Gizmos.color = Color.yellow;
Vector3 fovLeft = Quaternion.Euler(0, -fieldOfView * 0.5f, 0) * transform.forward * detectionRadius;
Vector3 fovRight = Quaternion.Euler(0, fieldOfView * 0.5f, 0) * transform.forward * detectionRadius;
Gizmos.DrawLine(transform.position, transform.position + fovLeft);
Gizmos.DrawLine(transform.position, transform.position + fovRight);
}
#endif
}