197 lines
No EOL
5.6 KiB
C#
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;
|
|
}
|
|
} |