293 lines
10 KiB
C#
293 lines
10 KiB
C#
using System.Collections;
|
|
using UnityEngine;
|
|
|
|
/// <summary>
|
|
/// 盾卫技能:圣盾壁垒体系(1/3/6/10 级完整阶梯)
|
|
/// 1级【圣盾壁垒】:举盾生成 35% 最大生命值的护盾(持续 5s),挂 MagicShieldBlue 特效
|
|
/// 3级【坚不可摧】:护盾厚度提升至 50% 最大生命值,持续时间延长至 6s
|
|
/// 6级【战吼嘲讽】:技能拍地 OnSkillHit1 瞬间爆发 NovaBlue 蓝色声波冲击环,强制周围 4 米所有敌人攻击自己 3s!
|
|
/// 10级【圣盾清算】:护盾期间霸体免眩晕;当护盾被打破或超时结束时爆发神圣冲击波,将吸收伤害的 50% 转化为真实伤害反弹全场!
|
|
/// </summary>
|
|
public class ShieldGuardSkill : UnitSkill
|
|
{
|
|
[Header("护盾配置")]
|
|
[Tooltip("基础护盾持续时间(秒)")]
|
|
public float baseShieldDuration = 5.0f;
|
|
|
|
[Tooltip("3级以上护盾持续时间(秒)")]
|
|
public float upgradedShieldDuration = 6.0f;
|
|
|
|
[Header("6级战吼嘲讽配置")]
|
|
[Tooltip("嘲讽半径(米)")]
|
|
public float tauntRadius = 4.0f;
|
|
|
|
[Tooltip("嘲讽持续时间(秒)")]
|
|
public float tauntDuration = 3.0f;
|
|
|
|
[Header("特效资源")]
|
|
public GameObject shieldVfxPrefab; // 护盾特效 (MagicShieldBlue)
|
|
public GameObject tauntWaveVfxPrefab; // 拍地嘲讽声波环特效 (NovaBlue)
|
|
public GameObject shieldBurstVfxPrefab; // 破盾清算冲击波特效 (NovaLightningBlue 或 TargetHitExplosion)
|
|
|
|
private GameObject activeShieldVfx;
|
|
private Coroutine activeShieldCoroutine;
|
|
private float totalAbsorbedDamage = 0f;
|
|
private bool isSkillPending = false;
|
|
private float currentMaxShield = 0f;
|
|
|
|
private void EnsureUnit()
|
|
{
|
|
if (unit == null)
|
|
{
|
|
unit = GetComponent<UnitBase>();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 当能量蓄满时触发:播放盾卫专属技能动画(举盾蓄力后砸地)
|
|
/// </summary>
|
|
public override void ReleaseSkill()
|
|
{
|
|
EnsureUnit();
|
|
if (unit == null) return;
|
|
|
|
WorldHealthBar healthBar = unit.GetComponent<WorldHealthBar>();
|
|
if (healthBar == null || healthBar.IsDead) return;
|
|
|
|
unit.FaceCurrentTarget(0f);
|
|
isSkillPending = true;
|
|
|
|
// 播放盾卫技能动画,并在 1.09s 的 OnSkillHit1 帧触发核心效果
|
|
unit.PlaySkillAnimation(OnSkillAnimationFinished, 1.87f);
|
|
Debug.Log($"<color=cyan>盾卫开始吟唱技能【圣盾壁垒】</color>,等待 OnSkillHit1 拍地!");
|
|
}
|
|
|
|
/// <summary>
|
|
/// 动画事件帧方法:在双手持盾猛烈砸地的瞬间触发 (1.095 秒处)
|
|
/// </summary>
|
|
public void OnSkillHit1()
|
|
{
|
|
if (!isSkillPending) return;
|
|
isSkillPending = false;
|
|
|
|
EnsureUnit();
|
|
if (unit == null) return;
|
|
|
|
WorldHealthBar healthBar = unit.GetComponent<WorldHealthBar>();
|
|
if (healthBar == null || healthBar.IsDead) return;
|
|
|
|
int level = unit.level;
|
|
|
|
// 1. 计算护盾数值 (1级 35%, 3级+ 50%)
|
|
float ratio = level >= 3 ? 0.50f : 0.35f;
|
|
float shieldAmount = healthBar.maxHealth * ratio;
|
|
currentMaxShield = shieldAmount;
|
|
totalAbsorbedDamage = 0f;
|
|
|
|
// 2. 赋予自身护盾
|
|
healthBar.AddShield(shieldAmount);
|
|
|
|
// 3. 挂载护盾环绕特效 (MagicShieldBlue)
|
|
PlayShieldVfx();
|
|
|
|
// 4. 10 级解锁:霸体免疫眩晕
|
|
StatusEffectController statusCtrl = unit.GetComponent<StatusEffectController>();
|
|
if (level >= 10 && statusCtrl != null)
|
|
{
|
|
statusCtrl.isStunImmune = true;
|
|
}
|
|
|
|
// 5. 6 级解锁:拍地激发声波光环 + 强力嘲讽周围 4 米所有敌人
|
|
if (level >= 6)
|
|
{
|
|
ExecuteTauntAndWave();
|
|
}
|
|
|
|
// 6. 监听护盾伤害吸收 (用于 10 级破盾清算)
|
|
healthBar.OnShieldAbsorbedDamage -= RecordAbsorbedDamage;
|
|
healthBar.OnShieldAbsorbedDamage += RecordAbsorbedDamage;
|
|
|
|
// 7. 启动护盾生命周期协程 (监测破盾与超时结算)
|
|
float duration = level >= 3 ? upgradedShieldDuration : baseShieldDuration;
|
|
if (activeShieldCoroutine != null)
|
|
{
|
|
StopCoroutine(activeShieldCoroutine);
|
|
}
|
|
activeShieldCoroutine = StartCoroutine(ShieldLifecycleRoutine(duration, shieldAmount));
|
|
|
|
Debug.Log($"<color=cyan>【盾卫】拍地爆发!</color> 获得护盾 {shieldAmount:F1} (等级: {level})");
|
|
}
|
|
|
|
private void ExecuteTauntAndWave()
|
|
{
|
|
// 播放声波光环特效 (NovaBlue)
|
|
PlayTauntWaveVfx();
|
|
|
|
// 范围嘲讽所有敌人
|
|
UnitTeam myTeam = unit.GetComponent<UnitTeam>();
|
|
UnitBase[] allUnits = FindObjectsOfType<UnitBase>();
|
|
float radiusSq = tauntRadius * tauntRadius;
|
|
int tauntedCount = 0;
|
|
|
|
foreach (var other in allUnits)
|
|
{
|
|
if (other == null || other == unit || !other.gameObject.activeInHierarchy || other.IsDead) continue;
|
|
UnitTeam otherTeam = other.GetComponent<UnitTeam>();
|
|
if (myTeam != null && otherTeam != null && !myTeam.IsEnemy(otherTeam.gameObject)) continue; // 只嘲讽敌方
|
|
|
|
Vector3 diff = other.transform.position - unit.transform.position;
|
|
diff.y = 0f;
|
|
if (diff.sqrMagnitude <= radiusSq)
|
|
{
|
|
other.ApplyTaunt(unit.gameObject, tauntDuration);
|
|
tauntedCount++;
|
|
}
|
|
}
|
|
|
|
Debug.Log($"<color=yellow>【盾卫战吼嘲讽】激发!</color> 强制嘲讽周围 {tauntedCount} 个敌人持续 {tauntDuration:F1} 秒!");
|
|
}
|
|
|
|
private void RecordAbsorbedDamage(float absorbed)
|
|
{
|
|
totalAbsorbedDamage += absorbed;
|
|
}
|
|
|
|
private IEnumerator ShieldLifecycleRoutine(float duration, float initialShieldAmount)
|
|
{
|
|
float timer = duration;
|
|
WorldHealthBar healthBar = unit != null ? unit.GetComponent<WorldHealthBar>() : null;
|
|
StatusEffectController statusCtrl = unit != null ? unit.GetComponent<StatusEffectController>() : null;
|
|
|
|
while (timer > 0f)
|
|
{
|
|
if (unit == null || healthBar == null || healthBar.IsDead || healthBar.currentShield <= 0f)
|
|
{
|
|
break;
|
|
}
|
|
timer -= Time.deltaTime;
|
|
yield return null;
|
|
}
|
|
|
|
// 护盾解除/破盾清算
|
|
bool isShieldBroken = healthBar != null && healthBar.currentShield <= 0f && timer > 0f;
|
|
int level = unit != null ? unit.level : 1;
|
|
|
|
// 10 级解锁【圣盾清算】:将吸收的伤害按 50% 转化为真实伤害反弹全场周围
|
|
if (level >= 10 && totalAbsorbedDamage > 0f && unit != null)
|
|
{
|
|
TriggerShieldBurst(totalAbsorbedDamage * 0.50f);
|
|
}
|
|
|
|
// 清理状态与特效
|
|
if (statusCtrl != null)
|
|
{
|
|
statusCtrl.isStunImmune = false;
|
|
}
|
|
|
|
if (healthBar != null)
|
|
{
|
|
healthBar.OnShieldAbsorbedDamage -= RecordAbsorbedDamage;
|
|
if (timer <= 0f && healthBar.currentShield > 0f)
|
|
{
|
|
healthBar.RemoveShield(initialShieldAmount);
|
|
}
|
|
}
|
|
|
|
if (activeShieldVfx != null)
|
|
{
|
|
Destroy(activeShieldVfx);
|
|
activeShieldVfx = null;
|
|
}
|
|
|
|
Debug.Log($"<color=cyan>【盾卫】护盾结算完毕</color> (是否被击破: {isShieldBroken}, 总共吸收伤害: {totalAbsorbedDamage:F1})");
|
|
}
|
|
|
|
private void TriggerShieldBurst(float burstDamage)
|
|
{
|
|
Debug.Log($"<color=yellow>【圣盾清算】护盾爆发!</color> 造成 {burstDamage:F1} 范围反击真实伤害!");
|
|
|
|
// 播放破盾爆发特效
|
|
PlayShieldBurstVfx();
|
|
|
|
// 对周围 4 米造成反弹伤害
|
|
if (unit != null)
|
|
{
|
|
unit.ApplyAreaSkillDamage(tauntRadius, burstDamage, false);
|
|
}
|
|
}
|
|
|
|
private void PlayShieldVfx()
|
|
{
|
|
if (activeShieldVfx != null) Destroy(activeShieldVfx);
|
|
|
|
GameObject prefab = shieldVfxPrefab;
|
|
#if UNITY_EDITOR
|
|
if (prefab == null)
|
|
{
|
|
prefab = UnityEditor.AssetDatabase.LoadAssetAtPath<GameObject>("Assets/TJGeneratorLibEffects/Prefabs/Combat/Magic/Shield/MagicShieldBlue.prefab");
|
|
}
|
|
#endif
|
|
if (prefab != null && unit != null)
|
|
{
|
|
activeShieldVfx = Instantiate(prefab, unit.transform.position + Vector3.up * 1.0f, Quaternion.identity);
|
|
activeShieldVfx.transform.SetParent(unit.transform, true);
|
|
}
|
|
}
|
|
|
|
private void PlayTauntWaveVfx()
|
|
{
|
|
GameObject prefab = tauntWaveVfxPrefab;
|
|
#if UNITY_EDITOR
|
|
if (prefab == null)
|
|
{
|
|
prefab = UnityEditor.AssetDatabase.LoadAssetAtPath<GameObject>("Assets/TJGeneratorLibEffects/Prefabs/Combat/Nova/Standard/NovaBlue.prefab");
|
|
}
|
|
#endif
|
|
if (prefab != null && unit != null)
|
|
{
|
|
Vector3 spawnPos = unit.transform.position;
|
|
spawnPos.y = 0.05f; // 贴地
|
|
var vfx = Instantiate(prefab, spawnPos, prefab.transform.rotation);
|
|
// 调整 scale 以匹配 4 米嘲讽范围
|
|
vfx.transform.localScale = new Vector3(1.6f, 1.6f, 1.6f);
|
|
Destroy(vfx, 2.5f);
|
|
}
|
|
}
|
|
|
|
private void PlayShieldBurstVfx()
|
|
{
|
|
GameObject prefab = shieldBurstVfxPrefab;
|
|
#if UNITY_EDITOR
|
|
if (prefab == null)
|
|
{
|
|
prefab = UnityEditor.AssetDatabase.LoadAssetAtPath<GameObject>("Assets/TJGeneratorLibEffects/Prefabs/Combat/Nova/Lightning/NovaLightningBlue.prefab");
|
|
}
|
|
#endif
|
|
if (prefab != null && unit != null)
|
|
{
|
|
Vector3 spawnPos = unit.transform.position;
|
|
spawnPos.y = 0.05f;
|
|
var vfx = Instantiate(prefab, spawnPos, prefab.transform.rotation);
|
|
vfx.transform.localScale = new Vector3(1.5f, 1.5f, 1.5f);
|
|
Destroy(vfx, 2.5f);
|
|
}
|
|
}
|
|
|
|
private void OnSkillAnimationFinished()
|
|
{
|
|
isSkillPending = false;
|
|
}
|
|
|
|
private void OnDestroy()
|
|
{
|
|
if (activeShieldVfx != null) Destroy(activeShieldVfx);
|
|
if (unit != null)
|
|
{
|
|
WorldHealthBar healthBar = unit.GetComponent<WorldHealthBar>();
|
|
if (healthBar != null) healthBar.OnShieldAbsorbedDamage -= RecordAbsorbedDamage;
|
|
StatusEffectController statusCtrl = unit.GetComponent<StatusEffectController>();
|
|
if (statusCtrl != null) statusCtrl.isStunImmune = false;
|
|
}
|
|
}
|
|
}
|