/*
* author: ryan lin
* date: 30/7/2024
* description: 'standard' npc ai behaviour
*/
using System.Collections;
using UnityEngine;
using UnityEngine.AI;
using Random = System.Random;
///
/// 'standard' npc ai behaviour
///
public class AI : MonoBehaviour
{
///
/// to save resources when referring to the speed of this AI if its human
///
private static readonly int AnimatorSpeed = Animator.StringToHash("Speed");
///
/// set the layers the AI can be on
///
public LayerMask walkableLayers;
///
/// the destination coordinate of the AI
///
public Vector3 destinationCoord;
///
/// the range that the AI can set as their destination
///
public int movingRange;
///
/// the nav mash agent that is on this AI
///
private NavMeshAgent _agent;
///
/// the animator that is attached to this AI if applicable
///
private Animator _animator;
///
/// the current state that the AI is at this point in time
///
private string _currentState;
///
/// a bool to check if the destination point is set
///
private bool _destinationPointSet;
///
/// the state that the AI will be on the next update
///
private string _nextState;
///
/// to set initial values
///
public void Awake()
{
_animator = GetComponent();
_currentState = "Strolling";
_agent = GetComponent();
_animator = GetComponent();
_currentState = "Strolling";
_nextState = _currentState;
ChangeState();
}
///
/// to update the speed of the AI to the animator each frame and to update any state changes to the AI
///
public void Update()
{
_animator.SetFloat(AnimatorSpeed, _agent.velocity.magnitude);
_currentState = _nextState;
}
///
/// to change the scene when needed
///
private void ChangeState()
{
StartCoroutine(_currentState);
}
///
/// to set a random x and y coordinate for the AI to go to
///
private void SearchWalkPoint()
{
var rand = new Random();
float randomX = rand.Next(-movingRange * 100, movingRange * 100);
float randomZ = rand.Next(-movingRange * 100, movingRange * 100);
destinationCoord = new Vector3(
transform.position.x + randomX / 100,
transform.position.y,
transform.position.z + randomZ / 100
);
if (Physics.Raycast(destinationCoord, -transform.up, 2f, walkableLayers)) _destinationPointSet = true;
}
///
/// a state that the AI wonders around using the SearchWalkPoint function to find a location for the AI to go to
///
private IEnumerator Strolling()
{
SearchWalkPoint();
while (_currentState == "Strolling")
{
if (!_destinationPointSet)
SearchWalkPoint();
else
_agent.SetDestination(destinationCoord);
if ((transform.position - destinationCoord).magnitude < 1f) _destinationPointSet = false;
yield return new WaitForSeconds(1f);
}
ChangeState();
}
}