using System;
using System.Collections;
using UnityEngine;
using BaseGames.Core;
using BaseGames.Core.Pool;
namespace BaseGames.Enemies.Abilities
{
///
/// 闪烁突袭能力:消失后瞬移到目标侧后方/上方/侧翼,现身后衔接出手。
///
/// 流程:
/// 1. 选择闪烁目标点(玩家侧后 / 上方 / 侧翼,依 )
/// 2. 隐身(隐藏 SpriteRenderer、关闭碰撞、播放消失 VFX)
/// 3. 等待 disappearDuration 营造"消失"感
/// 4. 瞬移到目标点
/// 5. 现身 + 出现 VFX + 预警闪光(reappearTelegraph)
/// 6. 调用 followUpAbilityId 指定的能力作为出手(若为空则播放 attackSequence[0])
///
/// 同时实现 for :
/// 当 PathBerserker2d 路径包含 teleport NavLink 时,本能力接管穿越逻辑,
/// 播放消失/出现动画后告知 NavAgent 继续路径,而不触发战斗出手。
///
public sealed class BlinkStrikeAbility : EnemyAbilityBase, INavLinkHandler
{
public enum BlinkPosition { BehindTarget, FrontTarget, AboveTarget, FlankTarget }
[Header("闪烁参数")]
[SerializeField] private BlinkPosition _blinkPosition = BlinkPosition.BehindTarget;
[SerializeField] private float _offsetDistance = 1.8f;
[SerializeField] private float _verticalOffsetAbove = 3.0f;
[SerializeField] private float _disappearDuration = 0.25f;
[SerializeField] private float _reappearTelegraph = 0.20f;
[SerializeField] private LayerMask _groundMask;
[SerializeField] private float _groundSnapMaxDistance = 3f;
[Header("视觉")]
[SerializeField] private SpriteRenderer[] _renderers;
[SerializeField] private Collider2D[] _disableDuringBlink;
[SerializeField] private string _disappearVfxKey = "";
[SerializeField] private string _appearVfxKey = "";
[Header("出手能力(在现身后触发,若为空则播放第一段攻击动画)")]
[SerializeField] private string _followUpAbilityId = "";
private Rigidbody2D _rb;
private IObjectPoolService _pool;
private Coroutine _navLinkCoroutine;
// ── INavLinkHandler(Teleport 连接段穿越)─────────────────────
private static readonly NavLinkType[] _handledTypes = new[] { NavLinkType.Teleport };
public NavLinkType[] HandledLinkTypes => _handledTypes;
public bool CanHandleLink(NavLinkType type, Vector2 linkStart, Vector2 linkEnd) => true;
public void BeginLinkTraversal(NavLinkType type, Vector2 linkStart, Vector2 linkEnd, Action onComplete)
{
if (_navLinkCoroutine != null) StopCoroutine(_navLinkCoroutine);
_navLinkCoroutine = StartCoroutine(TeleportNavLinkCoroutine(linkEnd, onComplete));
}
public void AbortLinkTraversal()
{
if (_navLinkCoroutine != null) { StopCoroutine(_navLinkCoroutine); _navLinkCoroutine = null; }
SetVisible(true);
}
/// 纯导航用传送:消失 → 移动到连接终点 → 出现,不触发战斗出手。
private IEnumerator TeleportNavLinkCoroutine(Vector2 destination, Action onComplete)
{
_pool ??= ServiceLocator.GetOrDefault();
if (!string.IsNullOrEmpty(_disappearVfxKey))
_pool?.Spawn(_disappearVfxKey, _transform.position, Quaternion.identity);
SetVisible(false);
if (_rb != null) _rb.velocity = Vector2.zero;
yield return EnemyAbilityWaits.Get(_disappearDuration);
if (_rb != null) _rb.position = destination;
else _transform.position = destination;
SetVisible(true);
if (!string.IsNullOrEmpty(_appearVfxKey))
_pool?.Spawn(_appearVfxKey, _transform.position, Quaternion.identity);
_navLinkCoroutine = null;
onComplete?.Invoke(); // 通知 EnemyNavAgent → CompleteLinkTraversal
}
protected override void Awake()
{
base.Awake();
_rb = GetComponentInParent();
if (_renderers == null || _renderers.Length == 0)
_renderers = GetComponentsInChildren(true);
}
protected override IEnumerator ExecuteCoroutine()
{
_pool ??= ServiceLocator.GetOrDefault();
var target = _enemy != null ? _enemy.PlayerTransform : null;
if (target == null) yield break;
// 1. 消失
if (!string.IsNullOrEmpty(_disappearVfxKey))
_pool?.Spawn(_disappearVfxKey, _transform.position, Quaternion.identity);
SetVisible(false);
if (_rb != null) _rb.velocity = Vector2.zero;
yield return EnemyAbilityWaits.Get(_disappearDuration);
// 2. 选目标点 + 瞬移
Vector2 dest = ComputeBlinkPosition(target);
if (_rb != null) _rb.position = dest;
else _transform.position = dest;
FaceTarget(target);
// 3. 现身 + 预警
SetVisible(true);
if (!string.IsNullOrEmpty(_appearVfxKey))
_pool?.Spawn(_appearVfxKey, _transform.position, Quaternion.identity);
Phase = AbilityRunState.Telegraph;
yield return EnemyAbilityWaits.Get(_reappearTelegraph);
// 4. 出手
Phase = AbilityRunState.Active;
if (!string.IsNullOrEmpty(_followUpAbilityId) && _enemy != null)
{
var follow = _enemy.Abilities.Get(_followUpAbilityId);
if (follow != null)
{
follow.Execute();
while (follow.IsRunning) yield return null;
yield break;
}
}
// 退化路径:播放第一段动画
var seq = _config != null ? _config.attackSequence : null;
if (seq != null && seq.Length > 0)
{
var atk = seq[0];
float dur = atk.fallbackDuration;
if (atk.clip != null && _animancer != null)
{
var st = _animancer.Play(atk.clip);
if (st != null && st.Length > 0f) dur = st.Length;
}
yield return EnemyAbilityWaits.Get(dur);
}
}
protected override void OnInterrupted(InterruptReason reason)
{
// 中断时同时终止 NavLink 穿越协程(若正在进行),防止 onComplete 回调污染导航状态
AbortLinkTraversal();
}
private Vector2 ComputeBlinkPosition(Transform target)
{
Vector2 t = target.position;
Vector2 selfDir = (t - (Vector2)_transform.position);
float facing = selfDir.x >= 0f ? 1f : -1f;
Vector2 raw;
switch (_blinkPosition)
{
case BlinkPosition.FrontTarget: raw = t + new Vector2(facing * _offsetDistance, 0f); break;
case BlinkPosition.AboveTarget: raw = t + new Vector2(0f, _verticalOffsetAbove); break;
case BlinkPosition.FlankTarget:
raw = t + new Vector2((UnityEngine.Random.value < 0.5f ? -1f : 1f) * _offsetDistance, 0f);
break;
case BlinkPosition.BehindTarget:
default:
float tFacing = target.localScale.x >= 0f ? 1f : -1f;
raw = t - new Vector2(tFacing * _offsetDistance, 0f);
break;
}
// 贴地(避免悬空)
var hit = Physics2D.Raycast(raw + Vector2.up * 0.5f, Vector2.down,
_groundSnapMaxDistance + 0.5f, _groundMask);
if (hit.collider != null) raw.y = hit.point.y + 0.05f;
return raw;
}
private void SetVisible(bool visible)
{
if (_renderers != null)
for (int i = 0; i < _renderers.Length; i++)
if (_renderers[i] != null) _renderers[i].enabled = visible;
if (_disableDuringBlink != null)
for (int i = 0; i < _disableDuringBlink.Length; i++)
if (_disableDuringBlink[i] != null) _disableDuringBlink[i].enabled = visible;
}
}
}