/* * author: ryan lin * date: 30/7/2024 * description: 'standard' npc ai behaviour */ using System.Collections; using UnityEngine; using UnityEngine.AI; using Random = System.Random; /// <summary> /// TODO /// </summary> public class AI : MonoBehaviour { /// <summary> /// to save resources when referring to the speed of this AI if its human /// </summary> private static readonly int AnimatorSpeed = Animator.StringToHash("Speed"); /// <summary> /// set the layers the AI can be on /// </summary> public LayerMask walkableLayers; /// <summary> /// the destination coordinate of the AI /// </summary> public Vector3 destinationCoord; /// <summary> /// the range that the AI can set as their destination /// </summary> public int movingRange; /// <summary> /// the nav mash agent that is on this AI /// </summary> private NavMeshAgent _agent; /// <summary> /// the animator that is attached to this AI if applicable /// </summary> private Animator _animator; /// <summary> /// the current state that the AI is at this point in time /// </summary> private string _currentState; /// <summary> /// a bool to check if the destination point is set /// </summary> private bool _destinationPointSet; /// <summary> /// the state that the AI will be on the next update /// </summary> private string _nextState; /// <summary> /// to set initial values /// </summary> public void Awake() { _animator = GetComponent<Animator>(); _currentState = "Strolling"; _agent = GetComponent<NavMeshAgent>(); _animator = GetComponent<Animator>(); _currentState = "Strolling"; _nextState = _currentState; ChangeState(); } /// <summary> /// to update the speed of the AI to the animator each frame and to update any state changes to the AI /// </summary> public void Update() { _animator.SetFloat(AnimatorSpeed, _agent.velocity.magnitude); _currentState = _nextState; } /// <summary> /// to change the scene when needed /// </summary> private void ChangeState() { StartCoroutine(_currentState); } /// <summary> /// to set a random x and y coordinate for the AI to go to /// </summary> 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; } /// <summary> /// a state that the AI wonders around using the SearchWalkPoint function to find a location for the AI to go to /// </summary> 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(); } }