using UnityEngine;
using PathBerserker2d;
using BaseGames.Enemies;
using System;
using System.Collections.Generic;
namespace BaseGames.Enemies.Navigation
{
///
/// PathBerserker2d 导航代理包装器(架构 07_EnemyModule §5 能力驱动版)。
///
/// 设计原则:
///
/// - 连接段穿越(跳跃/攀爬/传送等)委托给 能力组件执行
/// - 能力自行驱动动画 + 物理,本组件只做"调度 → 等回调 → 通知 PB2d 继续"
/// - 无对应能力时自动回退到 TransformBasedMovement(兜底行为)
/// - Awake 自动发现 GameObject 上的全部 INavLinkHandler,并禁用 TBM 对应 FeatureFlag
///
///
[RequireComponent(typeof(NavAgent))]
[RequireComponent(typeof(TransformBasedMovement))]
public class EnemyNavAgent : MonoBehaviour, IPathAgent
{
// ── 序列化 ──────────────────────────────────────────────────────
[Tooltip("边缘检测前向距离(m)")]
[SerializeField] private float _edgeCheckFwdOffset = 0.3f;
[Tooltip("边缘检测向下射线长度(m)")]
[SerializeField] private float _edgeCheckDownLen = 0.6f;
[Tooltip("边缘检测 LayerMask(留空 = 所有层)")]
[SerializeField] private LayerMask _groundMask = ~0;
// ── IPathAgent 公开状态 ────────────────────────────────────────
public bool IsMoving => _navAgent != null && _navAgent.IsFollowingAPath;
public bool IsOnLink => _navAgent != null && _navAgent.IsOnLink;
public NavLinkType CurrentLinkType => _currentLinkType;
public Vector2 CurrentLinkStart => _currentLinkStart;
public Vector2 CurrentLinkEnd => _currentLinkEnd;
// ── IPathAgent 事件 ────────────────────────────────────────────
public event Action OnLinkStarted;
public event Action OnLinkCompleted;
public event Action OnNavPathFailed;
public event Action OnGoalReached;
// ── 私有 ────────────────────────────────────────────────────────
private NavAgent _navAgent;
private TransformBasedMovement _movement;
// 能力 handler 注册表(NavLinkType → INavLinkHandler)
private readonly Dictionary _handlers
= new Dictionary();
private INavLinkHandler _activeHandler;
// 连接段状态缓存
private NavLinkType _currentLinkType = NavLinkType.None;
private Vector2 _currentLinkStart;
private Vector2 _currentLinkEnd;
// ── 初始化 ─────────────────────────────────────────────────────
private void Awake()
{
_navAgent = GetComponent();
_movement = GetComponent();
// 自动发现 INavLinkHandler 组件并注册(包含子对象)
foreach (var handler in GetComponentsInChildren(true))
RegisterLinkHandler(handler);
_navAgent.OnStartLinkTraversal += HandleLinkStart;
_navAgent.OnSegmentTraversal += HandleSegmentTraversal;
_navAgent.OnFailedToFindPath += HandlePathFailed;
_navAgent.OnReachedGoal += HandleGoalReached;
}
private void OnDestroy()
{
if (_navAgent == null) return;
_navAgent.OnStartLinkTraversal -= HandleLinkStart;
_navAgent.OnSegmentTraversal -= HandleSegmentTraversal;
_navAgent.OnFailedToFindPath -= HandlePathFailed;
_navAgent.OnReachedGoal -= HandleGoalReached;
}
// ── Handler 注册 ───────────────────────────────────────────────
///
/// 注册能力为某连接段类型的处理器。
/// 注册后 TransformBasedMovement 中对应 FeatureFlag 将被禁用,由能力全权负责该类型穿越。
///
public void RegisterLinkHandler(INavLinkHandler handler)
{
if (handler == null) return;
foreach (var type in handler.HandledLinkTypes)
{
_handlers[type] = handler;
// 禁用 TBM 对该类型的处理,完全交给能力
var flag = TypeToFeatureFlag(type);
if (flag != 0 && _movement != null)
_movement.enabledFeatures &= ~flag;
}
}
/// 移除某处理器(例如能力被永久禁用时)。TBM FeatureFlag 自动恢复。
public void UnregisterLinkHandler(INavLinkHandler handler)
{
if (handler == null) return;
foreach (var type in handler.HandledLinkTypes)
{
if (_handlers.TryGetValue(type, out var registered) && ReferenceEquals(registered, handler))
{
_handlers.Remove(type);
// 恢复 TBM 对该类型的处理
var flag = TypeToFeatureFlag(type);
if (flag != 0 && _movement != null)
_movement.enabledFeatures |= flag;
}
}
}
// ── IPathAgent ─────────────────────────────────────────────────
public void RequestMoveTo(Vector2 target) => _navAgent?.UpdatePath(target);
public void StopNavigation()
{
_activeHandler?.AbortLinkTraversal();
_activeHandler = null;
_navAgent?.Stop();
}
public bool IsAtDestination() => _navAgent == null || _navAgent.IsIdle;
public void SetSpeed(float speed)
{
if (_movement != null) _movement.movementSpeed = speed;
}
public bool CanReach(Vector2 target) => _navAgent?.CanReach(target) ?? false;
public bool WalkToRandom() => _navAgent?.SetRandomDestination() ?? false;
public bool IsNearEdge()
{
var origin = (Vector2)transform.position;
var facing = transform.localScale.x >= 0f ? Vector2.right : Vector2.left;
return !Physics2D.Raycast(origin + facing * _edgeCheckFwdOffset,
Vector2.down, _edgeCheckDownLen, _groundMask);
}
// ── 底层 NavAgent 直接访问 ──────────────────────────────────────
/// 原始 PB2d NavAgent,供需要 PB2d 高级功能的能力直接使用。
public NavAgent RawNavAgent => _navAgent;
// ── 连接段调度核心 ─────────────────────────────────────────────
private void HandleLinkStart(NavAgent agent)
{
var seg = agent.CurrentPathSegment;
_currentLinkType = ParseLinkType(seg?.link?.LinkTypeName);
_currentLinkStart = seg?.LinkStart ?? Vector2.zero;
_currentLinkEnd = seg?.LinkEnd ?? Vector2.zero;
OnLinkStarted?.Invoke(_currentLinkType);
if (_handlers.TryGetValue(_currentLinkType, out var handler))
{
if (handler.CanHandleLink(_currentLinkType, _currentLinkStart, _currentLinkEnd))
{
_activeHandler = handler;
handler.BeginLinkTraversal(_currentLinkType, _currentLinkStart, _currentLinkEnd,
onComplete: () =>
{
_activeHandler = null;
_navAgent?.CompleteLinkTraversal();
});
return;
}
// CanHandleLink 返回 false 且 TBM 已禁用 → NavAgent 会卡住,警告设计者
Debug.LogWarning($"[EnemyNavAgent] '{handler.GetType().Name}' reported CanHandleLink=false " +
$"for {_currentLinkType} (TBM disabled). NavAgent may stall. " +
$"Check link distance/height vs. ability parameters.", this);
}
// 无 handler → TBM 兜底(其 FeatureFlag 仍开启)
}
private void HandleSegmentTraversal(NavAgent agent)
{
if (_currentLinkType != NavLinkType.None && !agent.IsOnLink)
{
var finished = _currentLinkType;
_currentLinkType = NavLinkType.None;
_currentLinkStart = Vector2.zero;
_currentLinkEnd = Vector2.zero;
OnLinkCompleted?.Invoke(finished);
}
}
private void HandlePathFailed(NavAgent _) => OnNavPathFailed?.Invoke();
private void HandleGoalReached(NavAgent _) => OnGoalReached?.Invoke();
// ── 工具 ───────────────────────────────────────────────────────
private static NavLinkType ParseLinkType(string name) => name switch
{
"corner" => NavLinkType.Corner,
"jump" => NavLinkType.Jump,
"fall" => NavLinkType.Fall,
"teleport" => NavLinkType.Teleport,
"climb" => NavLinkType.Climb,
"elevator" => NavLinkType.Elevator,
null or "" => NavLinkType.Segment,
_ => NavLinkType.Custom
};
/// NavLinkType → TransformBasedMovement.FeatureFlags 映射。
private static TransformBasedMovement.FeatureFlags TypeToFeatureFlag(NavLinkType type) => type switch
{
NavLinkType.Jump => TransformBasedMovement.FeatureFlags.JumpLinks,
NavLinkType.Fall => TransformBasedMovement.FeatureFlags.FallLinks,
NavLinkType.Corner => TransformBasedMovement.FeatureFlags.CornerLinks,
NavLinkType.Climb => TransformBasedMovement.FeatureFlags.ClimbLinks,
NavLinkType.Elevator => TransformBasedMovement.FeatureFlags.ElevatorLinks,
NavLinkType.Teleport => TransformBasedMovement.FeatureFlags.TeleportLinks,
_ => (TransformBasedMovement.FeatureFlags)0
};
}
}