EnemyAI.cs 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  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;
  12. public float damagePerSecond = 20f;
  13. [Header("Hover Settings")]
  14. public float hoverHeight = 2.0f; // Distance above the ground
  15. public float hoverSmoothness = 5f; // Lower = smoother/floatier
  16. private Vector3 spawnPosition;
  17. public List<Vector3> patrolPoints = new List<Vector3>();
  18. private int currentPointIndex = 0;
  19. private Transform player;
  20. private LayerMask terrainLayer;
  21. void Start()
  22. {
  23. player = GameObject.FindGameObjectWithTag("Player").transform;
  24. terrainLayer = LayerMask.GetMask("Terrain");
  25. spawnPosition = transform.position;
  26. GeneratePatrolPoints();
  27. }
  28. void GeneratePatrolPoints()
  29. {
  30. patrolPoints.Clear();
  31. for (int i = 0; i < 3; i++)
  32. {
  33. // Raycast from high up to find the ground
  34. Vector3 randomPos = spawnPosition + new Vector3(Random.Range(-15f, 15f), 20f, Random.Range(-15f, 15f));
  35. if (Physics.Raycast(randomPos, Vector3.down, out RaycastHit hit, 50f, terrainLayer))
  36. {
  37. // We add the hoverHeight to the patrol point so they don't dive toward the grass
  38. patrolPoints.Add(hit.point + Vector3.up * hoverHeight);
  39. }
  40. }
  41. }
  42. void Update()
  43. {
  44. float distToPlayer = Vector3.Distance(transform.position, player.position);
  45. float distFromHome = Vector3.Distance(transform.position, spawnPosition);
  46. if (distToPlayer < detectionRadius && distFromHome < maxChaseDistance)
  47. {
  48. currentState = EnemyState.Chase;
  49. }
  50. else if (distFromHome > maxChaseDistance || (currentState == EnemyState.Chase && distToPlayer > detectionRadius))
  51. {
  52. currentState = EnemyState.Returning;
  53. }
  54. if (currentState == EnemyState.Returning && distFromHome < 2f)
  55. {
  56. currentState = EnemyState.Patrol;
  57. }
  58. ExecuteState();
  59. if (currentState == EnemyState.Chase && distToPlayer < 2.0f) // Slightly increased range for floating enemies
  60. {
  61. PlayerStats stats = player.GetComponent<PlayerStats>();
  62. if (stats != null) stats.TakeDamage(damagePerSecond * Time.deltaTime);
  63. }
  64. }
  65. void ExecuteState()
  66. {
  67. switch (currentState)
  68. {
  69. case EnemyState.Patrol:
  70. Patrol();
  71. break;
  72. case EnemyState.Chase:
  73. MoveTowards(player.position, chaseSpeed);
  74. break;
  75. case EnemyState.Returning:
  76. MoveTowards(spawnPosition, patrolSpeed);
  77. break;
  78. }
  79. }
  80. void Patrol()
  81. {
  82. if (patrolPoints.Count == 0)
  83. {
  84. GeneratePatrolPoints();
  85. return;
  86. }
  87. Vector3 target = patrolPoints[currentPointIndex];
  88. MoveTowards(target, patrolSpeed);
  89. // Check distance in 3D space now that we hover
  90. if (Vector3.Distance(transform.position, target) < 2.0f)
  91. currentPointIndex = (currentPointIndex + 1) % patrolPoints.Count;
  92. }
  93. void MoveTowards(Vector3 target, float speed)
  94. {
  95. // 1. Horizontal Direction
  96. Vector3 dir = (target - transform.position).normalized;
  97. dir.y = 0;
  98. // Obstacle avoidance (nudge direction if hitting a steep hill)
  99. RaycastHit wallHit;
  100. if (Physics.Raycast(transform.position + Vector3.up * 0.5f, dir, out wallHit, 1.5f, terrainLayer))
  101. {
  102. dir += wallHit.normal * 0.5f;
  103. }
  104. // 2. Apply Move
  105. transform.position += dir * speed * Time.deltaTime;
  106. // 3. Floating / Height Adjustment
  107. // Fire ray from above the enemy to find the ground directly beneath it
  108. if (Physics.Raycast(transform.position + Vector3.up * 10f, Vector3.down, out RaycastHit groundHit, 30f, terrainLayer))
  109. {
  110. float targetHeight = groundHit.point.y + hoverHeight;
  111. // Use Lerp for a floaty, smooth height change
  112. float newY = Mathf.Lerp(transform.position.y, targetHeight, Time.deltaTime * hoverSmoothness);
  113. transform.position = new Vector3(transform.position.x, newY, transform.position.z);
  114. }
  115. // 4. Rotation
  116. if (dir != Vector3.zero)
  117. {
  118. Quaternion targetRotation = Quaternion.LookRotation(dir);
  119. transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, Time.deltaTime * 5f);
  120. }
  121. }
  122. }