Advertisement
leomovskii

EnemyController

Mar 15th, 2025
262
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 4.48 KB | None | 0 0
  1. using System;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. using UnityEngine.AI;
  5.  
  6. [RequireComponent(typeof(NavMeshAgent))]
  7. public class EnemyController : MonoBehaviour {
  8.  
  9.     enum EnemyState {
  10.         Idle, // просто стоїть
  11.         Pursuit, // переслідує ціль
  12.         Battle // атакує
  13.     }
  14.  
  15.     public Transform aimPoint;
  16.     public Inventory inventory;
  17.  
  18.     public float aggroDistance;
  19.     public float alertDistance;
  20.  
  21.     private NavMeshAgent agent;
  22.  
  23.     private EnemyState state;
  24.     private Vector3 lastPlayerSeenLocation;
  25.  
  26.     private readonly RaycastHit[] _hits = new RaycastHit[10];
  27.  
  28.     private void Awake() {
  29.         agent = GetComponent<NavMeshAgent>();
  30.         lastPlayerSeenLocation = transform.position;
  31.     }
  32.  
  33.     private void Update() {
  34.         var playerLocation = PlayerController.Me.transform.position;
  35.  
  36.         bool playerSeenAtThisUpdate = false;
  37.  
  38.         state = EnemyState.Idle;
  39.         // Якщо гравець в зоні бачення ворогу
  40.         if (Vector3.Distance(aimPoint.position, PlayerController.Me.aimPoint.position) <= aggroDistance) {
  41.             Vector3 direction = (PlayerController.Me.aimPoint.position - aimPoint.position).normalized;
  42.             Ray ray = new Ray(aimPoint.position, direction);
  43.             int hits = Physics.RaycastNonAlloc(ray, _hits, aggroDistance);
  44.             Array.Sort(_hits, 0, hits, new RaycastHitComparer(ray.origin));
  45.  
  46.             // Якщо між ворогом і гравцем нема перешкод
  47.             if (_hits[0].transform != null && CompareLayer(_hits[0].transform.gameObject, PlayerController.Me.playerLayer)) {
  48.                 playerSeenAtThisUpdate = true;
  49.  
  50.                 // Ворог дивиться на гравця
  51.                 Vector3 lookPos = new Vector3(PlayerController.Me.aimPoint.position.x, transform.position.y, PlayerController.Me.aimPoint.position.z);
  52.                 transform.LookAt(lookPos);
  53.                 lastPlayerSeenLocation = playerLocation;
  54.  
  55.                 state = EnemyState.Battle;
  56.             } else
  57.                 state = EnemyState.Pursuit;
  58.  
  59.         } else if (Vector3.Distance(transform.position, lastPlayerSeenLocation) > 1f) {
  60.             state = EnemyState.Pursuit;
  61.         }
  62.  
  63.         if (state == EnemyState.Idle) {
  64.             lastPlayerSeenLocation = transform.position; // загубив гравця
  65.             agent.SetDestination(transform.position); // бот зупиняється
  66.             if (inventory != null) // бот не атакує
  67.                 inventory.SetFiring(false);
  68.  
  69.         } else if (state == EnemyState.Pursuit) {
  70.             agent.SetDestination(lastPlayerSeenLocation); // ворог йде туди, де він бачив гравця
  71.             if (inventory != null) // бот не атакує
  72.                 inventory.SetFiring(false);
  73.             if (playerSeenAtThisUpdate)
  74.                 NotifyOthers(playerLocation);
  75.  
  76.         } else { // battle
  77.             agent.SetDestination(transform.position); // бот зупиняється
  78.             if (inventory != null) // бот атакує
  79.                 inventory.SetFiring(true);
  80.             if (playerSeenAtThisUpdate)
  81.                 NotifyOthers(playerLocation);
  82.         }
  83.     }
  84.  
  85.     private void NotifyOthers(Vector3 lastPlayerSeenLocation) {
  86.         EnemyController[] allBots = FindObjectsOfType<EnemyController>();
  87.         for (int i = 0; i < allBots.Length; i++) {
  88.             if (allBots[i] != this && Vector3.Distance(transform.position, allBots[i].transform.position) <= alertDistance) {
  89.                 allBots[i].SayThatPlayerHasBeenInPosition(lastPlayerSeenLocation);
  90.             }
  91.         }
  92.     }
  93.  
  94.     public void SayThatPlayerHasBeenInPosition(Vector3 lastPlayerSeenLocation) {
  95.         this.lastPlayerSeenLocation = lastPlayerSeenLocation;
  96.     }
  97.  
  98.     private void OnDrawGizmosSelected() {
  99.         if (aimPoint != null) {
  100.             Gizmos.color = new Color(0f, 1f, 1f, 0.2f);
  101.             Gizmos.DrawSphere(aimPoint.position, aggroDistance);
  102.         }
  103.  
  104.         var player = FindObjectOfType<PlayerController>();
  105.         if (Physics.Linecast(aimPoint.position, player.aimPoint.position, out RaycastHit hit)) {
  106.             Gizmos.color = Color.blue;
  107.             Gizmos.DrawLine(aimPoint.position, player.aimPoint.position);
  108.         }
  109.     }
  110.  
  111.     private static bool CompareLayer(GameObject target, LayerMask layers) {
  112.         return ((1 << target.layer) & layers) != 0;
  113.     }
  114. }
  115.  
  116. public class RaycastHitComparer : IComparer<RaycastHit> {
  117.     private Vector3 origin;
  118.  
  119.     public RaycastHitComparer(Vector3 origin) {
  120.         this.origin = origin;
  121.     }
  122.  
  123.     public int Compare(RaycastHit x, RaycastHit y) {
  124.         bool xIsValid = x.collider != null;
  125.         bool yIsValid = y.collider != null;
  126.  
  127.         if (!xIsValid && !yIsValid)
  128.             return 0;
  129.  
  130.         if (!xIsValid)
  131.             return 1;
  132.  
  133.         if (!yIsValid)
  134.             return -1;
  135.  
  136.         float distanceX = Vector3.Distance(origin, x.point);
  137.         float distanceY = Vector3.Distance(origin, y.point);
  138.  
  139.         return distanceX.CompareTo(distanceY);
  140.     }
  141. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement