chunk 1: core gameplay scripts scenes runtime assets
This commit is contained in:
145
Assets/Scripts/AI/Navigation/AINavigationHelper.cs
Normal file
145
Assets/Scripts/AI/Navigation/AINavigationHelper.cs
Normal file
@@ -0,0 +1,145 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.AI;
|
||||
|
||||
/// <summary>
|
||||
/// AINavigationHelper — NavMeshAgent wrapper with path caching and mobile optimization.
|
||||
/// Prevents unnecessary path recalculations and provides clean navigation API.
|
||||
///
|
||||
/// Only recalculates path when target moves >2m or path becomes invalid.
|
||||
/// </summary>
|
||||
public class AINavigationHelper : MonoBehaviour
|
||||
{
|
||||
[Header("Navigation Settings")]
|
||||
[SerializeField] private float pathRecalcThreshold = 2f; // Minimum target movement to recalc
|
||||
[SerializeField] private float stoppingDistance = 1.5f;
|
||||
[SerializeField] private float reachThreshold = 2f;
|
||||
|
||||
[Header("Avoidance")]
|
||||
[SerializeField] private int avoidancePriority = 50; // 0=highest priority, 99=lowest
|
||||
|
||||
// ─── Components ──────────────────────────────────────────
|
||||
private NavMeshAgent _agent;
|
||||
private CharacterAIController _aiController;
|
||||
|
||||
// ─── Path Cache ──────────────────────────────────────────
|
||||
private Vector3 _lastTargetPosition;
|
||||
private bool _hasDestination;
|
||||
|
||||
// ─── Properties ──────────────────────────────────────────
|
||||
public bool HasArrived => _hasDestination && _agent != null && _agent.enabled &&
|
||||
!_agent.pathPending &&
|
||||
_agent.remainingDistance <= reachThreshold;
|
||||
|
||||
public bool IsNavigating => _hasDestination && _agent != null && _agent.enabled &&
|
||||
_agent.hasPath && _agent.remainingDistance > reachThreshold;
|
||||
|
||||
public float RemainingDistance => _agent != null && _agent.enabled ? _agent.remainingDistance : float.MaxValue;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
_agent = GetComponent<NavMeshAgent>();
|
||||
_aiController = GetComponent<CharacterAIController>();
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
if (_agent != null)
|
||||
{
|
||||
_agent.stoppingDistance = stoppingDistance;
|
||||
_agent.avoidancePriority = avoidancePriority;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Navigate to a position. Only recalculates path if target moved significantly.
|
||||
/// </summary>
|
||||
public void SetDestination(Vector3 target)
|
||||
{
|
||||
// Use CharacterAIController if available (it handles NavMesh warping)
|
||||
if (_aiController != null)
|
||||
{
|
||||
float sqrDist = (target - _lastTargetPosition).sqrMagnitude;
|
||||
if (_hasDestination && sqrDist < pathRecalcThreshold * pathRecalcThreshold)
|
||||
return; // Target hasn't moved enough, keep current path
|
||||
|
||||
_aiController.NavigateTo(target);
|
||||
_lastTargetPosition = target;
|
||||
_hasDestination = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// Direct NavMeshAgent fallback
|
||||
if (_agent == null || !_agent.enabled) return;
|
||||
|
||||
float sqrDistDirect = (target - _lastTargetPosition).sqrMagnitude;
|
||||
if (_hasDestination && sqrDistDirect < pathRecalcThreshold * pathRecalcThreshold)
|
||||
return;
|
||||
|
||||
_agent.SetDestination(target);
|
||||
_lastTargetPosition = target;
|
||||
_hasDestination = true;
|
||||
}
|
||||
|
||||
/// <summary>Stop navigation immediately.</summary>
|
||||
public void Stop()
|
||||
{
|
||||
if (_aiController != null)
|
||||
{
|
||||
_aiController.Stop();
|
||||
}
|
||||
else if (_agent != null && _agent.enabled)
|
||||
{
|
||||
_agent.ResetPath();
|
||||
}
|
||||
|
||||
_hasDestination = false;
|
||||
}
|
||||
|
||||
/// <summary>Check if destination is approximately reached.</summary>
|
||||
public bool HasReachedDestination()
|
||||
{
|
||||
if (!_hasDestination) return true;
|
||||
|
||||
if (_agent != null && _agent.enabled)
|
||||
{
|
||||
return !_agent.pathPending && _agent.remainingDistance <= reachThreshold;
|
||||
}
|
||||
|
||||
// Fallback distance check
|
||||
return Vector3.SqrMagnitude(transform.position - _lastTargetPosition) < reachThreshold * reachThreshold;
|
||||
}
|
||||
|
||||
/// <summary>Set avoidance priority (carriers get higher priority = lower number).</summary>
|
||||
public void SetAvoidancePriority(int priority)
|
||||
{
|
||||
avoidancePriority = priority;
|
||||
if (_agent != null) _agent.avoidancePriority = priority;
|
||||
}
|
||||
|
||||
/// <summary>Set movement speed.</summary>
|
||||
public void SetSpeed(float speed)
|
||||
{
|
||||
if (_agent != null) _agent.speed = speed;
|
||||
}
|
||||
|
||||
/// <summary>Warp to a position on the NavMesh.</summary>
|
||||
public bool WarpTo(Vector3 position)
|
||||
{
|
||||
if (_agent == null) return false;
|
||||
|
||||
NavMeshHit hit;
|
||||
if (NavMesh.SamplePosition(position, out hit, 5f, NavMesh.AllAreas))
|
||||
{
|
||||
_agent.Warp(hit.position);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>Force path recalculation on next SetDestination call.</summary>
|
||||
public void InvalidatePath()
|
||||
{
|
||||
_lastTargetPosition = Vector3.zero;
|
||||
_hasDestination = false;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user