File size: 3,838 Bytes
6cae93f | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 | using UnityEngine;
using UnityEngine.AI;
namespace UnityAgent
{
/// <summary>
/// AI NPC that wanders between random points and chases the player when
/// they enter the aggro radius. Uses Unity's NavMeshAgent.
/// </summary>
[RequireComponent(typeof(NavMeshAgent))]
public class NPCController : MonoBehaviour
{
public enum State { Idle, Wander, Chase }
[Header("References")]
public Transform player;
[Header("Behaviour")]
public State initialState = State.Wander;
public float wanderRadius = 20f;
public float aggroRange = 12f;
public float loseSightRange = 20f;
public float idleDuration = 2f;
public float wanderSpeed = 2.5f;
public float chaseSpeed = 5f;
[Header("Debug")]
public bool drawGizmos = true;
private NavMeshAgent _agent;
private State _state;
private float _stateTimer;
private Vector3 _startPos;
private void Awake()
{
_agent = GetComponent<NavMeshAgent>();
_agent.speed = wanderSpeed;
}
private void Start()
{
_state = initialState;
_startPos = transform.position;
if (player == null && GameObject.FindGameObjectWithTag("Player") != null)
player = GameObject.FindGameObjectWithTag("Player").transform;
}
private void Update()
{
switch (_state)
{
case State.Idle: TickIdle(); break;
case State.Wander: TickWander(); break;
case State.Chase: TickChase(); break;
}
}
private void TickIdle()
{
_stateTimer -= Time.deltaTime;
if (PlayerInRange(aggroRange)) { EnterChase(); return; }
if (_stateTimer <= 0f) EnterWander();
}
private void TickWander()
{
if (PlayerInRange(aggroRange)) { EnterChase(); return; }
if (_agent.remainingDistance <= _agent.stoppingDistance && !_agent.pathPending)
EnterIdle();
}
private void TickChase()
{
if (player == null) { EnterWander(); return; }
_agent.SetDestination(player.position);
if (!PlayerInRange(loseSightRange)) EnterWander();
}
private void EnterIdle()
{
_state = State.Idle;
_stateTimer = idleDuration;
_agent.isStopped = true;
}
private void EnterWander()
{
_state = State.Wander;
_agent.speed = wanderSpeed;
_agent.isStopped = false;
Vector3 dir = Random.insideUnitSphere * wanderRadius;
dir.y = 0f;
Vector3 target = _startPos + dir;
if (NavMesh.SamplePosition(target, out NavMeshHit hit, wanderRadius, NavMesh.AllAreas))
_agent.SetDestination(hit.position);
}
private void EnterChase()
{
_state = State.Chase;
_agent.speed = chaseSpeed;
_agent.isStopped = false;
}
private bool PlayerInRange(float range)
{
if (player == null) return false;
return Vector3.Distance(transform.position, player.position) <= range;
}
private void OnDrawGizmosSelected()
{
if (!drawGizmos) return;
Gizmos.color = Color.yellow;
Gizmos.DrawWireSphere(transform.position, aggroRange);
Gizmos.color = Color.red;
Gizmos.DrawWireSphere(transform.position, loseSightRange);
Gizmos.color = Color.green;
Gizmos.DrawWireSphere(_startPos == Vector3.zero ? transform.position : _startPos, wanderRadius);
}
}
}
|