EnemyAI.cs 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. using UnityEngine;
  2. using System.Collections.Generic;
  3. public class EnemyAI : MonoBehaviour
  4. {
  5. public enum EnemyState { Patrol, Chase, Returning }
  6. public EnemyState currentState = EnemyState.Patrol;
  7. [Header("Movement Settings")]
  8. public float patrolSpeed = 3f;
  9. public float chaseSpeed = 6f;
  10. public float detectionRadius = 12f;
  11. public float maxChaseDistance = 30f; // The "Leash" length
  12. private Vector3 spawnPosition;
  13. public List<Vector3> patrolPoints = new List<Vector3>();
  14. private int currentPointIndex = 0;
  15. private Transform player;
  16. private LayerMask terrainLayer;
  17. void Start()
  18. {
  19. player = GameObject.FindGameObjectWithTag("Player").transform;
  20. // Looking for the "Terrain" layer specifically as per your Spawner
  21. terrainLayer = LayerMask.GetMask("Terrain");
  22. spawnPosition = transform.position; // Remember where it was born
  23. // Generate 3 patrol points around spawn
  24. for (int i = 0; i < 3; i++)
  25. {
  26. Vector3 randomPos = spawnPosition + new Vector3(Random.Range(-15f, 15f), 10f, Random.Range(-15f, 15f));
  27. if (Physics.Raycast(randomPos, Vector3.down, out RaycastHit hit, 20f, terrainLayer))
  28. {
  29. patrolPoints.Add(hit.point + Vector3.up * 1f);
  30. }
  31. }
  32. }
  33. void Update()
  34. {
  35. float distToPlayer = Vector3.Distance(transform.position, player.position);
  36. float distFromHome = Vector3.Distance(transform.position, spawnPosition);
  37. // State Logic
  38. if (currentState == EnemyState.Chase && distFromHome > maxChaseDistance)
  39. {
  40. currentState = EnemyState.Returning;
  41. }
  42. else if (distToPlayer < detectionRadius && currentState != EnemyState.Returning)
  43. {
  44. currentState = EnemyState.Chase;
  45. }
  46. else if (currentState == EnemyState.Returning && distFromHome < 2f)
  47. {
  48. currentState = EnemyState.Patrol;
  49. }
  50. ExecuteState();
  51. }
  52. void ExecuteState()
  53. {
  54. switch (currentState)
  55. {
  56. case EnemyState.Patrol:
  57. Patrol();
  58. break;
  59. case EnemyState.Chase:
  60. MoveTowards(player.position, chaseSpeed);
  61. break;
  62. case EnemyState.Returning:
  63. MoveTowards(spawnPosition, patrolSpeed);
  64. break;
  65. }
  66. }
  67. void Patrol()
  68. {
  69. if (patrolPoints.Count == 0) return;
  70. Vector3 target = patrolPoints[currentPointIndex];
  71. MoveTowards(target, patrolSpeed);
  72. if (Vector3.Distance(transform.position, target) < 1.5f)
  73. currentPointIndex = (currentPointIndex + 1) % patrolPoints.Count;
  74. }
  75. void MoveTowards(Vector3 target, float speed)
  76. {
  77. Vector3 dir = (target - transform.position).normalized;
  78. dir.y = 0;
  79. // 1. Check for obstacles directly in front
  80. // We fire a ray from the "chest" of the enemy forward
  81. RaycastHit wallHit;
  82. if (Physics.Raycast(transform.position + Vector3.up * 1f, dir, out wallHit, 1.5f, terrainLayer))
  83. {
  84. // If the hill is too steep, we try to "step up" or slide along it
  85. dir += wallHit.normal * 0.5f;
  86. }
  87. // 2. Apply movement
  88. transform.position += dir * speed * Time.deltaTime;
  89. // 3. Ground Hugging (Smooth height adjustment)
  90. // We use a longer ray and a SmoothDamp or Lerp to prevent snapping
  91. if (Physics.Raycast(transform.position + Vector3.up * 10f, Vector3.down, out RaycastHit groundHit, 20f, terrainLayer))
  92. {
  93. float targetHeight = groundHit.point.y + 0.5f;
  94. // Smoothly transition the Y position so they don't "teleport" up hills
  95. float newY = Mathf.MoveTowards(transform.position.y, targetHeight, speed * Time.deltaTime);
  96. transform.position = new Vector3(transform.position.x, newY, transform.position.z);
  97. }
  98. // 4. Rotation (Make them face where they are going)
  99. if (dir != Vector3.zero)
  100. {
  101. Quaternion targetRotation = Quaternion.LookRotation(dir);
  102. transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, Time.deltaTime * 5f);
  103. }
  104. }
  105. }