Making FPS Enemy AI in Unity 3D

We will explore how to create an FPS (First Person Shooter) Enemy AI (Artificial Intelligence) using Unity 3D game engine (2021.3.XXXX). We will cover the implementation of different AI behaviors such as patrol, chase, and attack.

# Setting up Variables first

// Variables
 /////////////
 private bool walkPointSet;
 private bool alreadyAttacked;
 private bool playerInSightRange;
 private bool playerInAttackRange;

 private Transform player;
 private Vector3 walkPoint;
 private NavMeshAgent agent;

 [Header("Values")]
 [SerializeField] private float fireRate;
 [SerializeField] private float sightRange;
 [SerializeField] private float attackRange;
 [SerializeField] private float walkPointRange;

 [Header("Components")]
 [SerializeField] private LayerMask groundLayer;
 [SerializeField] private LayerMask playerLayer;

## Getting Components

// References
 //////////////
 private void Start()
 {
     agent = GetComponent<NavMeshAgent>(); // Getting navmesh agent
     player = GameObject.FindGameObjectWithTag("Player").transform; // Getting player body
 }

## Doing checks for player state like patroling, chase player & attack player

private void FixedUpdate()
 {
     playerInSightRange = Physics.CheckSphere(transform.position, sightRange, playerLayer); // Checking if player is in sight range
     playerInAttackRange = Physics.CheckSphere(transform.position, attackRange, playerLayer); // Checking if player is in attack range

     if (!playerInSightRange && !playerInAttackRange) Patroling(); // Start petroling
     if (playerInSightRange && !playerInAttackRange) ChasePlayer(); // Chasing player
     if (playerInSightRange && playerInAttackRange) AttackPlayer(); // Attacking player
 }

## Code for Patroling

private void Patroling()
 {
     if (!walkPointSet) SearchWalkPoint(); // If no walkpoint is set
     else if (walkPointSet)
         agent.SetDestination(walkPoint);

     // Serching walk poing
     void SearchWalkPoint()
     {
         float randomZ = Random.Range(-walkPointRange, walkPointRange); // Random z range
         float randomX = Random.Range(-walkPointRange, walkPointRange); // Random x range

         walkPoint = new Vector3(transform.position.x + randomX, transform.position.y, transform.position.z + randomZ); // Getting random location

         // Setting walkpoint to true
         if (Physics.Raycast(walkPoint, -transform.up, Mathf.Infinity, groundLayer))
             walkPointSet = true;
     }

     // Getting distence left to walk
     Vector3 distanceToWalkPoint = transform.position - walkPoint;
     if (distanceToWalkPoint.magnitude < 1)
         walkPointSet = false; // Setting walkpoint to false
 }

## Code for chasing player

private void ChasePlayer() { agent.SetDestination(player.position); } // Chasing player

## Code for Attacking player

private void AttackPlayer()
 {
     // Stopping enemy from moving
     agent.SetDestination(transform.position);
     transform.LookAt(player); // Looking at player

     // If not attacked then attack
     if (!alreadyAttacked)
     {
         ////////////////////////
         /// Attack Code here ///
         ////////////////////////

         alreadyAttacked = true; // If attacked
         // Setting fireRate
         Invoke(nameof(ResetAttack), fireRate);
     }
 }

 // Resetting attack
 private void ResetAttack() { alreadyAttacked = false; }

# All Code at once

// Variables
 /////////////
 private bool walkPointSet;
 private bool alreadyAttacked;
 private bool playerInSightRange;
 private bool playerInAttackRange;

 private Transform player;
 private Vector3 walkPoint;
 private NavMeshAgent agent;

 [Header("Values")]
 [SerializeField] private float fireRate;
 [SerializeField] private float sightRange;
 [SerializeField] private float attackRange;
 [SerializeField] private float walkPointRange;

 [Header("Components")]
 [SerializeField] private LayerMask groundLayer;
 [SerializeField] private LayerMask playerLayer;

 // References
 //////////////
 private void Start()
 {
     agent = GetComponent<NavMeshAgent>(); // Getting navmesh agent
     player = GameObject.FindGameObjectWithTag("Player").transform; // Getting player body
 }

 private void FixedUpdate()
 {
     playerInSightRange = Physics.CheckSphere(transform.position, sightRange, playerLayer); // Checking if player is in sight range
     playerInAttackRange = Physics.CheckSphere(transform.position, attackRange, playerLayer); // Checking if player is in attack range

     if (!playerInSightRange && !playerInAttackRange) Patroling(); // Start petroling
     if (playerInSightRange && !playerInAttackRange) ChasePlayer(); // Chasing player
     if (playerInSightRange && playerInAttackRange) AttackPlayer(); // Attacking player
 }

 private void Patroling()
 {
     if (!walkPointSet) SearchWalkPoint(); // If no walkpoint is set
     else if (walkPointSet)
         agent.SetDestination(walkPoint);

     // Serching walk poing
     void SearchWalkPoint()
     {
         float randomZ = Random.Range(-walkPointRange, walkPointRange); // Random z range
         float randomX = Random.Range(-walkPointRange, walkPointRange); // Random x range

         walkPoint = new Vector3(transform.position.x + randomX, transform.position.y, transform.position.z + randomZ); // Getting random location

         // Setting walkpoint to true
         if (Physics.Raycast(walkPoint, -transform.up, Mathf.Infinity, groundLayer))
             walkPointSet = true;
     }

     // Getting distence left to walk
     Vector3 distanceToWalkPoint = transform.position - walkPoint;
     if (distanceToWalkPoint.magnitude < 1)
         walkPointSet = false; // Setting walkpoint to false
 }

 private void ChasePlayer() { agent.SetDestination(player.position); } // Chasing player

 private void AttackPlayer()
 {
     // Stopping enemy from moving
     agent.SetDestination(transform.position);
     transform.LookAt(player); // Looking at player

     // If not attacked then attack
     if (!alreadyAttacked)
     {
         ////////////////////////
         /// Attack Code here ///
         ////////////////////////

         alreadyAttacked = true; // If attacked
         // Setting fireRate
         Invoke(nameof(ResetAttack), fireRate);
     }
 }

 // Resetting attack
 private void ResetAttack() { alreadyAttacked = false; }

Comments



Thanks For Reading