This repository has been archived on 2024-07-09. You can view files and clone it, but cannot push or open issues or pull requests.
everellia/SheKnowsWhatYouAreToHerGame/Assets/Scripts/HerAI.cs

197 lines
No EOL
5.6 KiB
C#

/*
* author: mark joshwel
* date: 30/5/2024
* description: enemy AI based off <https://youtu.be/UjkSFoLxesw>
*/
using System;
using UnityEngine;
using UnityEngine.AI;
using Random = UnityEngine.Random;
/// <summary>
/// AI patrolling, chasing and capturing behaviour for the enemy
/// </summary>
public class HerAI : MonoBehaviour
{
/// <summary>
/// variable for the nav mesh agent that determines where the enemy can move
/// </summary>
public NavMeshAgent agent;
/// <summary>
/// variable for the player's position
/// </summary>
public Transform player;
/// <summary>
/// variables to distinguish ground and player for sensing
/// </summary>
public LayerMask whatIsGround, whatIsPlayer;
/// <summary>
/// patrolling: variable for the next point for her to walk to
/// </summary>
public Vector3 walkPoint;
/// <summary>
/// patrolling: variable for the range of the walk point
/// </summary>
public float walkPointRange;
/// <summary>
/// capturing: variable for the time range between captures
/// </summary>
public float timeBetweenCaptures;
/// <summary>
/// variable specifying the sight range of the enemy
/// </summary>
public float sightRange;
/// <summary>
/// variable specifying the attack range of the enemy
/// </summary>
public float attackRange;
/// <summary>
/// boolean variable for the player being in sight range
/// </summary>
public bool playerInSightRange;
/// <summary>
/// boolean variable for the player being in attack range
/// </summary>
public bool playerInCaptureRange;
/// <summary>
/// capturing: variable for if the enemy has attempted to capture the player
/// </summary>
private bool _attemptedCapture;
/// <summary>
/// variable to store game manager
/// </summary>
private GameManager _game;
/// <summary>
/// patrolling: variable to determine if the next point is set
/// </summary>
private bool _walkPointSet;
/// <summary>
/// </summary>
private void Awake()
{
player = GameObject.Find("PlayerObj").transform;
agent = GetComponent<NavMeshAgent>();
}
/// <summary>
/// </summary>
private void Update()
{
//Check for sight and attack range
playerInSightRange = Physics.CheckSphere(transform.position, sightRange, whatIsPlayer);
playerInCaptureRange = Physics.CheckSphere(transform.position, attackRange, whatIsPlayer);
if (!playerInSightRange && !playerInCaptureRange) Patrolling();
if (playerInSightRange && !playerInCaptureRange) ChasePlayer();
if (playerInCaptureRange && playerInSightRange) CapturePlayer();
}
/// <summary>
/// function to find and store the game manager
/// </summary>
/// <exception cref="Exception">generic exception when the object is in an unplayable state</exception>
private void OnEnable()
{
// get the game manager
_game = GameObject.Find("GameManager").GetComponent<GameManager>();
if (_game == null)
throw new Exception("HerAI: could not find GameManager (unreachable?)");
}
// /// <summary>
// /// function to destroy the enemy
// /// </summary>
// private void DestroyEnemy()
// {
// Destroy(gameObject);
// }
/// <summary>
/// function to draw/visualize the sight and attack range of the enemy
/// </summary>
private void OnDrawGizmosSelected()
{
Gizmos.color = Color.red;
Gizmos.DrawWireSphere(transform.position, attackRange);
Gizmos.color = Color.yellow;
Gizmos.DrawWireSphere(transform.position, sightRange);
}
/// <summary>
/// function handling patrolling behaviour
/// </summary>
private void Patrolling()
{
if (!_walkPointSet) SearchWalkPoint();
else agent.SetDestination(walkPoint);
// reached walk point
if ((transform.position - walkPoint).magnitude < 1f)
_walkPointSet = false;
}
/// <summary>
/// function to look for and set the next walk point
/// </summary>
private void SearchWalkPoint()
{
//Calculate random point in range
var randomZ = Random.Range(-walkPointRange, walkPointRange);
var randomX = Random.Range(-walkPointRange, walkPointRange);
walkPoint = new Vector3(transform.position.x + randomX, transform.position.y, transform.position.z + randomZ);
if (Physics.Raycast(walkPoint, -transform.up, 2f, whatIsGround))
_walkPointSet = true;
}
/// <summary>
/// function to chase the player
/// </summary>
private void ChasePlayer()
{
agent.SetDestination(player.position);
}
/// <summary>
/// function that captures the player and signals the game manager appropriately
/// </summary>
private void CapturePlayer()
{
// // don't move the enemy
// agent.SetDestination(transform.position);
// look at me!
transform.LookAt(player);
// are we under cooldown?
if (_attemptedCapture) return;
// signal the game manager to show the 'caught!' menu
_game.SetDisplayState(GameManager.DisplayState.ScreenCaughtMenu);
// set the cooldown
_attemptedCapture = true;
Invoke(nameof(ResetCapture), timeBetweenCaptures);
}
/// <summary>
/// function to reset the capture cooldown, called by <c>Invoke()</c>
/// </summary>
private void ResetCapture()
{
_attemptedCapture = false;
}
}