using UnityEngine;
using UnityEngine.AI;//Use unity ai
public class EnemyAI : MonoBehaviour
{
public NavMeshAgent enemyAI;
public Transform player;
public LayerMask whatIsGround, whatIsPlayer;
public GameObject projectile;
public float health;
//Enemy patrolling
public Vector3 patrolPoint;
public float patrolPointRange;
bool isPatrolPointSet;
//Enemy attacking
public float timeBetweenAttacks;
bool enemyAttacked;
//Enemy states
public float sightRange, attackRange;
public bool playerIsInSightRange, playerIsInAttackRange;
private void Start()
{
player = GameObject.Find("PlayerMesh").transform;//Find the player's position
enemyAI = GetComponent<NavMeshAgent>();//Get navmesh agent component of enemy
}
private void Update()
{
//check if enemy is in the sight and attack range
playerIsInSightRange = Physics.CheckSphere(transform.position, sightRange, whatIsPlayer);//Create a check sphere to check if player is in sight range
playerIsInAttackRange = Physics.CheckSphere(transform.position, attackRange, whatIsPlayer);//same as above, excepts check if in attack range
if (!playerIsInSightRange && !playerIsInAttackRange)//If player isnt in the sight range and attack range of enemy, patrol the area
{
Patrolling();//call patrol function
}
if (playerIsInSightRange && !playerIsInAttackRange)//if player is in the sight range but not in attack range, chase the player
{
ChasePlayer();//call chase function
}
if (playerIsInSightRange && playerIsInAttackRange)//If player is in attack and sight range, attack the player
{
AttackPlayer();//call attack function
}
}
private void Patrolling()
{
if (!isPatrolPointSet)//if there is no patrol perimiter set
{
SearchPatrolPoint();//we must search for a patrol point using this function
}
if (isPatrolPointSet)//if the patrol perimeter has been set
{
enemyAI.SetDestination(patrolPoint);//the enemy will now set its destination to the patrol point and move to it
}
Vector3 distanceToPatrolPoint = transform.position - patrolPoint;//calculates distance between enemy and patrol point
if(distanceToPatrolPoint.magnitude < 1f)//if the distance is less than 1, that means the enemy has reached the patrol point
{
isPatrolPointSet = false;//set point set to false, which will cause searchpatrolpoint function to be activated
}
}
private void SearchPatrolPoint()
{
float randomZ = Random.Range(-patrolPointRange, patrolPointRange);//Create a random patrol point on z axis for enemy to walk
float randomX = Random.Range(-patrolPointRange, patrolPointRange);//Create a random patrol point on x axis for enemy to walk
//Creating a patrol point using random x and z axis values added onto the enemy's current position
patrolPoint = new Vector3(transform.position.x + randomX, transform.position.y, transform.position.z + randomZ);
//the patrol point could be outside the map, so we must check it is on the ground by shootinga raycast
if (Physics.Raycast(patrolPoint, -transform.up, 2f, whatIsGround))
{
isPatrolPointSet = true;//the patrol point has been set, so we must set it to true
}
}
private void ChasePlayer()
{
enemyAI.SetDestination(player.position);//Enemy will walk towards the player's position
}
private void AttackPlayer()
{
enemyAI.SetDestination(transform.position);//Enemy will stop moving when attacking
transform.LookAt(player);//Enemy will look at the player when attacking
if (!enemyAttacked)//if the enemy has not been attacked
{
Rigidbody rb = Instantiate(projectile, transform.position, Quaternion.identity).GetComponent<Rigidbody>();
rb.AddForce(transform.forward * 32f, ForceMode.Impulse);
rb.AddForce(transform.up * 2f, ForceMode.Impulse);
enemyAttacked = true;//set enemy attacked to true
Invoke(nameof(ResetAttack), timeBetweenAttacks);//invoke the reset attack function after timebetweenattacks variable
}
}
private void ResetAttack()
{
enemyAttacked = false;//set enemy attack to false when resetting the attack of the enemy
}
public void TakeDamage(int damage)
{
health -= damage;
if (health<= 0)
{
Destroy(gameObject);
}
}
}