| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144 |
- using UnityEngine;
- using System.Collections.Generic;
- public class EnemyAI : MonoBehaviour
- {
- public enum EnemyState { Patrol, Chase, Returning }
- public EnemyState currentState = EnemyState.Patrol;
- [Header("Movement Settings")]
- public float patrolSpeed = 3f;
- public float chaseSpeed = 6f;
- public float detectionRadius = 12f;
- public float maxChaseDistance = 30f;
- public float damagePerSecond = 20f;
- [Header("Hover Settings")]
- public float hoverHeight = 2.0f; // Distance above the ground
- public float hoverSmoothness = 5f; // Lower = smoother/floatier
- private Vector3 spawnPosition;
- public List<Vector3> patrolPoints = new List<Vector3>();
- private int currentPointIndex = 0;
- private Transform player;
- private LayerMask terrainLayer;
- void Start()
- {
- player = GameObject.FindGameObjectWithTag("Player").transform;
- terrainLayer = LayerMask.GetMask("Terrain");
- spawnPosition = transform.position;
- GeneratePatrolPoints();
- }
- void GeneratePatrolPoints()
- {
- patrolPoints.Clear();
- for (int i = 0; i < 3; i++)
- {
- // Raycast from high up to find the ground
- Vector3 randomPos = spawnPosition + new Vector3(Random.Range(-15f, 15f), 20f, Random.Range(-15f, 15f));
- if (Physics.Raycast(randomPos, Vector3.down, out RaycastHit hit, 50f, terrainLayer))
- {
- // We add the hoverHeight to the patrol point so they don't dive toward the grass
- patrolPoints.Add(hit.point + Vector3.up * hoverHeight);
- }
- }
- }
- void Update()
- {
- float distToPlayer = Vector3.Distance(transform.position, player.position);
- float distFromHome = Vector3.Distance(transform.position, spawnPosition);
- if (distToPlayer < detectionRadius && distFromHome < maxChaseDistance)
- {
- currentState = EnemyState.Chase;
- }
- else if (distFromHome > maxChaseDistance || (currentState == EnemyState.Chase && distToPlayer > detectionRadius))
- {
- currentState = EnemyState.Returning;
- }
- if (currentState == EnemyState.Returning && distFromHome < 2f)
- {
- currentState = EnemyState.Patrol;
- }
- ExecuteState();
- if (currentState == EnemyState.Chase && distToPlayer < 2.0f) // Slightly increased range for floating enemies
- {
- PlayerStats stats = player.GetComponent<PlayerStats>();
- if (stats != null) stats.TakeDamage(damagePerSecond * Time.deltaTime);
- }
- }
- void ExecuteState()
- {
- switch (currentState)
- {
- case EnemyState.Patrol:
- Patrol();
- break;
- case EnemyState.Chase:
- MoveTowards(player.position, chaseSpeed);
- break;
- case EnemyState.Returning:
- MoveTowards(spawnPosition, patrolSpeed);
- break;
- }
- }
- void Patrol()
- {
- if (patrolPoints.Count == 0)
- {
- GeneratePatrolPoints();
- return;
- }
- Vector3 target = patrolPoints[currentPointIndex];
- MoveTowards(target, patrolSpeed);
- // Check distance in 3D space now that we hover
- if (Vector3.Distance(transform.position, target) < 2.0f)
- currentPointIndex = (currentPointIndex + 1) % patrolPoints.Count;
- }
- void MoveTowards(Vector3 target, float speed)
- {
- // 1. Horizontal Direction
- Vector3 dir = (target - transform.position).normalized;
- dir.y = 0;
- // Obstacle avoidance (nudge direction if hitting a steep hill)
- RaycastHit wallHit;
- if (Physics.Raycast(transform.position + Vector3.up * 0.5f, dir, out wallHit, 1.5f, terrainLayer))
- {
- dir += wallHit.normal * 0.5f;
- }
- // 2. Apply Move
- transform.position += dir * speed * Time.deltaTime;
- // 3. Floating / Height Adjustment
- // Fire ray from above the enemy to find the ground directly beneath it
- if (Physics.Raycast(transform.position + Vector3.up * 10f, Vector3.down, out RaycastHit groundHit, 30f, terrainLayer))
- {
- float targetHeight = groundHit.point.y + hoverHeight;
- // Use Lerp for a floaty, smooth height change
- float newY = Mathf.Lerp(transform.position.y, targetHeight, Time.deltaTime * hoverSmoothness);
- transform.position = new Vector3(transform.position.x, newY, transform.position.z);
- }
- // 4. Rotation
- if (dir != Vector3.zero)
- {
- Quaternion targetRotation = Quaternion.LookRotation(dir);
- transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, Time.deltaTime * 5f);
- }
- }
- }
|