open-world-city-unity / Assets /Scripts /NPCController.cs
ryzerrr's picture
Upload folder using huggingface_hub
6cae93f verified
Raw
History Blame Contribute Delete
3.84 kB
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);
}
}
}