165 lines
4.2 KiB
C#
165 lines
4.2 KiB
C#
using UnityEngine;
|
|
using UnityEngine.AI;
|
|
|
|
[RequireComponent(typeof(CharacterController))]
|
|
public class EnemyAI : MonoBehaviour
|
|
{
|
|
public CaptureZone[] zones;
|
|
public float moveSpeed = 3.5f;
|
|
public float retargetInterval = 2f;
|
|
public float stoppingDistance = 0.7f;
|
|
public float randomFactor = 4f;
|
|
|
|
private CharacterController characterController;
|
|
private NavMeshAgent navMeshAgent;
|
|
private CaptureZone targetZone;
|
|
private Vector3 targetOffset;
|
|
private float retargetTimer;
|
|
private Vector3 verticalVelocity;
|
|
|
|
private void Awake()
|
|
{
|
|
characterController = GetComponent<CharacterController>();
|
|
navMeshAgent = GetComponent<NavMeshAgent>();
|
|
|
|
if (navMeshAgent != null)
|
|
{
|
|
navMeshAgent.speed = moveSpeed;
|
|
navMeshAgent.stoppingDistance = stoppingDistance;
|
|
}
|
|
}
|
|
|
|
private void Start()
|
|
{
|
|
ChooseTarget();
|
|
}
|
|
|
|
private void Update()
|
|
{
|
|
retargetTimer -= Time.deltaTime;
|
|
|
|
if (targetZone == null || targetZone.GetOwner() == CaptureZone.Owner.Enemy || retargetTimer <= 0f)
|
|
{
|
|
ChooseTarget();
|
|
}
|
|
|
|
MoveToTarget();
|
|
}
|
|
|
|
private void ChooseTarget()
|
|
{
|
|
retargetTimer = retargetInterval + Random.Range(0f, 0.75f);
|
|
targetZone = null;
|
|
|
|
CaptureZone bestPlayerZone = FindBestZone(CaptureZone.Owner.Player);
|
|
if (bestPlayerZone != null)
|
|
{
|
|
SetTarget(bestPlayerZone);
|
|
return;
|
|
}
|
|
|
|
CaptureZone bestNeutralZone = FindBestZone(CaptureZone.Owner.Neutral);
|
|
if (bestNeutralZone != null)
|
|
{
|
|
SetTarget(bestNeutralZone);
|
|
}
|
|
}
|
|
|
|
private CaptureZone FindBestZone(CaptureZone.Owner owner)
|
|
{
|
|
if (zones == null || zones.Length == 0)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
CaptureZone best = null;
|
|
float bestScore = float.MaxValue;
|
|
|
|
for (int i = 0; i < zones.Length; i++)
|
|
{
|
|
CaptureZone zone = zones[i];
|
|
if (zone == null || zone.GetOwner() != owner)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
float distance = Vector3.Distance(transform.position, zone.transform.position);
|
|
float score = distance + Random.Range(0f, randomFactor);
|
|
if (score < bestScore)
|
|
{
|
|
bestScore = score;
|
|
best = zone;
|
|
}
|
|
}
|
|
|
|
return best;
|
|
}
|
|
|
|
private void SetTarget(CaptureZone zone)
|
|
{
|
|
targetZone = zone;
|
|
Vector2 randomCircle = Random.insideUnitCircle * 1.5f;
|
|
targetOffset = new Vector3(randomCircle.x, 0f, randomCircle.y);
|
|
|
|
if (CanUseNavMeshAgent())
|
|
{
|
|
navMeshAgent.SetDestination(GetTargetPosition());
|
|
}
|
|
}
|
|
|
|
private void MoveToTarget()
|
|
{
|
|
if (targetZone == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
Vector3 targetPosition = GetTargetPosition();
|
|
|
|
if (CanUseNavMeshAgent())
|
|
{
|
|
if (!navMeshAgent.hasPath || Vector3.Distance(navMeshAgent.destination, targetPosition) > 0.5f)
|
|
{
|
|
navMeshAgent.SetDestination(targetPosition);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
Vector3 direction = targetPosition - transform.position;
|
|
direction.y = 0f;
|
|
|
|
if (direction.magnitude <= stoppingDistance)
|
|
{
|
|
return;
|
|
}
|
|
|
|
Vector3 horizontalMove = direction.normalized * moveSpeed;
|
|
if (characterController.isGrounded && verticalVelocity.y < 0f)
|
|
{
|
|
verticalVelocity.y = -1f;
|
|
}
|
|
|
|
verticalVelocity.y += Physics.gravity.y * Time.deltaTime;
|
|
characterController.Move((horizontalMove + verticalVelocity) * Time.deltaTime);
|
|
|
|
if (horizontalMove.sqrMagnitude > 0.001f)
|
|
{
|
|
transform.rotation = Quaternion.LookRotation(horizontalMove.normalized, Vector3.up);
|
|
}
|
|
}
|
|
|
|
private Vector3 GetTargetPosition()
|
|
{
|
|
return targetZone.transform.position + targetOffset;
|
|
}
|
|
|
|
private bool CanUseNavMeshAgent()
|
|
{
|
|
return navMeshAgent != null &&
|
|
navMeshAgent.enabled &&
|
|
navMeshAgent.isActiveAndEnabled &&
|
|
navMeshAgent.isOnNavMesh;
|
|
}
|
|
}
|