Download examples/open_world_city/Assets/Scripts/NPCController.cs from ryzerrr/unity-game-agent: direct link, hf CLI and curl.
- Browser
- Download file 3.84 kB
-
https://huggingface.co/ryzerrr/unity-game-agent/resolve/main/examples/open_world_city/Assets/Scripts/NPCController.cs
- Command line
-
hf download hf://ryzerrr/unity-game-agent/examples/open_world_city/Assets/Scripts/NPCController.cs
-
curl -L -o NPCController.cs https://huggingface.co/ryzerrr/unity-game-agent/resolve/main/examples/open_world_city/Assets/Scripts/NPCController.cs
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> | |
| [] | |
| public class NPCController : MonoBehaviour | |
| { | |
| public enum State { Idle, Wander, Chase } | |
| [] | |
| public Transform player; | |
| [] | |
| 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; | |
| [] | |
| 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); | |
| } | |
| } | |
| } | |