Files
daluandou/Assets/Scripts/技能脚本/WerewolfSkill.cs
T
huadexuan 2ff98e8923 ```
feat(WerewolfSkill): 狂暴狼人技能系统重构为吸血战坦体系

- 实现完整的嗜血狂暴技能体系:1级嗜血狂暴、3级血脉沸腾、
  6级残虐血性、10级不灭狼王四个阶段
- 添加重抓撕咬动画效果和鲜血飞溅特效
- 实现扇形AOE撕裂攻击和吸血回复机制
- 添加背水一战机制:血量越低减伤和吸血越高
- 实现击杀刷新技能时间的连击机制
- 更新狼人定位从快速近战改为吸血战坦
- 添加全局单位击杀事件监听处理
```
2026-10-14 18:24:18 +08:00

400 lines
14 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 狂暴狼人技能:嗜血狂暴体系(吸血战坦 · 1/3/6/10 级完整阶梯)
/// 1级【嗜血狂暴】:重抓撕咬造成 150% 伤害(立即回复该次伤害 50% 生命);激活 5 秒【嗜血状态】,普攻吸血 +30%,攻速 +25%
/// 3级【血脉沸腾】:嗜血状态延长至 6.5 秒,期间普攻吸血提升至 45%,攻速 +35%,撕咬伤害提升至 190%
/// 6级【残虐血性】:撕咬升级为前方扇形 AOE 撕裂;嗜血期间触发【背水一战】:自身血量每降低 10%,伤害减免 +3%,普攻吸血额外 +5%
/// 10级【不灭狼王】:释放技能临时提升 35% 最大生命值上限及等额回血;技能期间只要击杀敌人,立即回复 20% 最大生命值并刷新嗜血时间!
/// </summary>
public class WerewolfSkill : UnitSkill
{
[Header("特效资源")]
[Tooltip("重抓抓痕特效 (SwordSlashMiniRed)")]
public GameObject clawSlashVfxPrefab;
[Tooltip("受击鲜血爆裂特效 (BloodExplosion)")]
public GameObject bloodHitVfxPrefab;
private bool isSkillPending = false;
private bool isBloodthirstActive = false;
private float bloodthirstTimer = 0f;
private float bloodthirstMaxDuration = 5f;
// 属性加成追踪与还原
private float baseBonusLifesteal = 0f;
private float dynamicLossLifesteal = 0f;
private float dynamicLossDamageReduction = 0f;
private float appliedAttackSpeedMultiplier = 1f;
private float temporaryBonusMaxHealth = 0f;
private void EnsureUnit()
{
if (unit == null)
{
unit = GetComponent<UnitBase>();
}
}
protected override void Awake()
{
base.Awake();
EnsureUnit();
}
private void Start()
{
EnsureUnit();
WorldHealthBar.OnUnitKilled += OnGlobalUnitKilled;
}
/// <summary>
/// 当能量蓄满时触发:播放大招攻击动画
/// </summary>
public override void ReleaseSkill()
{
EnsureUnit();
if (unit == null) return;
WorldHealthBar healthBar = unit.GetComponent<WorldHealthBar>();
if (healthBar == null || healthBar.IsDead) return;
if (unit.Target == null) return;
unit.FaceCurrentTarget(0f);
isSkillPending = true;
// 10级大招临时提升 35% 最大生命上限
if (unit.level >= 10 && temporaryBonusMaxHealth <= 0f)
{
temporaryBonusMaxHealth = healthBar.maxHealth * 0.35f;
healthBar.maxHealth += temporaryBonusMaxHealth;
healthBar.Heal(temporaryBonusMaxHealth);
Debug.Log($"<color=red>【不灭狼王】爆发!</color> 狼王之怒提升生命上限 +{temporaryBonusMaxHealth:F0} 并回血!");
}
// 播放大招攻击动画(挠击动作)
unit.PlaySkillAnimation(OnSkillAnimationFinished, 1.2f);
Debug.Log($"<color=red>【狂暴狼人】释放大招【嗜血狂暴】</color>,等待挠击命中帧!");
}
/// <summary>
/// 动画帧命中回调(兼容 OnAttackEffect 和 OnSkillHit1)
/// </summary>
public void OnSkillHit1()
{
ExecuteBiteStrike();
}
public void OnAttackEffect()
{
if (isSkillPending)
{
ExecuteBiteStrike();
}
}
/// <summary>
/// 实际结算大招重抓撕咬伤害与启动嗜血狂暴
/// </summary>
private void ExecuteBiteStrike()
{
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级 150%,3级+ 190%
float damageMultiplier = level >= 3 ? 1.90f : 1.50f;
float damage = unit.attackPower * damageMultiplier;
// 6级升级为扇形前方 AOE 撕咬,否则为单体重抓
if (level >= 6)
{
ExecuteCleaveBite(damage);
}
else
{
ExecuteSingleBite(damage);
}
// 激活【嗜血状态】
ActivateBloodthirst(level);
}
private void ExecuteSingleBite(float damage)
{
if (unit.Target == null) return;
GameObject target = unit.Target;
UnitBase targetUnit = target.GetComponentInParent<UnitBase>();
WorldHealthBar targetBar = target.GetComponentInParent<WorldHealthBar>();
PlayClawAndBloodVfx(target.transform.position + Vector3.up * 0.8f);
float dealtDamage = 0f;
if (targetUnit != null)
{
targetUnit.ReceiveDamage(damage, unit.gameObject);
dealtDamage = damage;
}
else if (targetBar != null)
{
targetBar.TakeDamage(damage, unit.gameObject);
dealtDamage = damage;
}
// 立即回复该次伤害 50% 的生命
WorldHealthBar myBar = unit.GetComponent<WorldHealthBar>();
if (myBar != null && dealtDamage > 0f)
{
float healAmount = dealtDamage * 0.5f;
myBar.Heal(healAmount);
Debug.Log($"<color=green>【嗜血狂暴】撕咬重创!</color> 造成 {dealtDamage:F1} 伤害,吸血回复 +{healAmount:F1} HP!");
}
}
private void ExecuteCleaveBite(float damage)
{
float cleaveRadius = 2.4f;
float cleaveAngle = 120f;
Vector3 forward = unit.transform.forward;
Vector3 myPos = unit.transform.position;
UnitTeam myTeam = unit.GetComponent<UnitTeam>();
var allTeams = FindObjectsOfType<UnitTeam>();
float totalDealt = 0f;
foreach (var t in allTeams)
{
if (t == null || !t.gameObject.activeInHierarchy || myTeam == null || !myTeam.IsEnemy(t.gameObject)) continue;
Vector3 toEnemy = t.transform.position - myPos;
toEnemy.y = 0f;
if (toEnemy.sqrMagnitude <= cleaveRadius * cleaveRadius)
{
float angle = Vector3.Angle(forward, toEnemy.normalized);
if (angle <= cleaveAngle * 0.5f)
{
PlayClawAndBloodVfx(t.transform.position + Vector3.up * 0.8f);
var targetUnit = t.GetComponentInParent<UnitBase>();
if (targetUnit != null)
{
targetUnit.ReceiveDamage(damage, unit.gameObject);
totalDealt += damage;
}
else
{
var bar = t.GetComponentInParent<WorldHealthBar>();
if (bar != null)
{
bar.TakeDamage(damage, unit.gameObject);
totalDealt += damage;
}
}
}
}
}
// 6级扇形撕裂吸血:回复总伤害的 50%
WorldHealthBar myBar = unit.GetComponent<WorldHealthBar>();
if (myBar != null && totalDealt > 0f)
{
float healAmount = totalDealt * 0.5f;
myBar.Heal(healAmount);
Debug.Log($"<color=green>【残虐血性】扇形撕裂!</color> 命中敌群造成 {totalDealt:F1} 伤害,吸血狂吸 +{healAmount:F1} HP!");
}
}
/// <summary>
/// 激活/刷新嗜血状态
/// </summary>
private void ActivateBloodthirst(int level)
{
float duration = level >= 3 ? 6.5f : 5.0f;
float bonusLifesteal = level >= 3 ? 0.45f : 0.30f;
float bonusAttackSpeed = level >= 3 ? 1.35f : 1.25f;
bloodthirstMaxDuration = duration;
bloodthirstTimer = duration;
if (!isBloodthirstActive)
{
isBloodthirstActive = true;
baseBonusLifesteal = bonusLifesteal;
unit.lifestealRate += baseBonusLifesteal;
appliedAttackSpeedMultiplier = bonusAttackSpeed;
unit.MultiplyAttackSpeed(appliedAttackSpeedMultiplier, 3.5f);
}
else
{
// 已在嗜血中时重置持续时间
bloodthirstTimer = duration;
}
Debug.Log($"<color=red>【嗜血状态激活】</color> 持续 {duration:F1} 秒:吸血 +{bonusLifesteal * 100:F0}%,攻速 +{(bonusAttackSpeed - 1f) * 100:F0}%!");
}
private void Update()
{
if (!isBloodthirstActive || unit == null) return;
bloodthirstTimer -= Time.deltaTime;
// 6级【背水一战】:嗜血期间自身血量越残,额外获得越高额的减伤与吸血
if (unit.level >= 6)
{
UpdateDesperationBuff();
}
if (bloodthirstTimer <= 0f)
{
EndBloodthirst();
}
}
/// <summary>
/// 6级【背水一战】:自身血量每降低 10%,减伤 +3%,吸血 +5%
/// </summary>
private void UpdateDesperationBuff()
{
WorldHealthBar healthBar = unit.GetComponent<WorldHealthBar>();
if (healthBar == null || healthBar.maxHealth <= 0f) return;
float lostHealthRatio = Mathf.Clamp01(1f - (healthBar.currentHealth / healthBar.maxHealth));
int lostTens = Mathf.FloorToInt(lostHealthRatio * 10f); // 每 10%
float targetReduction = lostTens * 0.03f; // 每 10% 减伤 +3% (最高 27%)
float targetExtraLifesteal = lostTens * 0.05f; // 每 10% 吸血 +5% (最高 45%)
// 差量动态更新,避免死循环累加
float deltaReduction = targetReduction - dynamicLossDamageReduction;
unit.damageReductionRate += deltaReduction;
dynamicLossDamageReduction = targetReduction;
float deltaLifesteal = targetExtraLifesteal - dynamicLossLifesteal;
unit.lifestealRate += deltaLifesteal;
dynamicLossLifesteal = targetExtraLifesteal;
}
private void EndBloodthirst()
{
if (!isBloodthirstActive) return;
isBloodthirstActive = false;
bloodthirstTimer = 0f;
// 还原属性
if (unit != null)
{
unit.lifestealRate = Mathf.Max(0f, unit.lifestealRate - baseBonusLifesteal - dynamicLossLifesteal);
unit.damageReductionRate = Mathf.Max(0f, unit.damageReductionRate - dynamicLossDamageReduction);
if (appliedAttackSpeedMultiplier > 1f)
{
unit.MultiplyAttackSpeed(1f / appliedAttackSpeedMultiplier, 3.5f);
}
// 10级大招临时提升的生命上限还原
if (temporaryBonusMaxHealth > 0f)
{
WorldHealthBar bar = unit.GetComponent<WorldHealthBar>();
if (bar != null)
{
bar.maxHealth = Mathf.Max(1f, bar.maxHealth - temporaryBonusMaxHealth);
bar.currentHealth = Mathf.Min(bar.currentHealth, bar.maxHealth);
}
temporaryBonusMaxHealth = 0f;
}
}
baseBonusLifesteal = 0f;
dynamicLossLifesteal = 0f;
dynamicLossDamageReduction = 0f;
appliedAttackSpeedMultiplier = 1f;
Debug.Log($"<color=gray>【嗜血状态结束】属性恢复正常。</color>");
}
/// <summary>
/// 10级【不灭狼王】:技能期间击杀敌人,立即回复 20% 最大生命值并刷新嗜血时间!
/// </summary>
private void OnGlobalUnitKilled(GameObject victim, GameObject killer)
{
if (!isBloodthirstActive || unit == null || killer == null) return;
if (unit.level < 10) return;
// 判断击杀者是否是自己
if (killer == unit.gameObject || killer.transform.IsChildOf(unit.transform))
{
WorldHealthBar myBar = unit.GetComponent<WorldHealthBar>();
if (myBar != null && !myBar.IsDead)
{
float heal = myBar.maxHealth * 0.20f;
myBar.Heal(heal);
// 重置/刷新嗜血持续时间
bloodthirstTimer = bloodthirstMaxDuration;
Debug.Log($"<color=red>【不灭狼王·猎杀连环】!</color> 击杀 {victim.name},立即回复 20% 生命 (+{heal:F0}) 并刷新狂暴状态!");
}
}
}
private void PlayClawAndBloodVfx(Vector3 position)
{
// 1. 鲜血飞溅
GameObject bloodPrefab = bloodHitVfxPrefab;
#if UNITY_EDITOR
if (bloodPrefab == null)
{
bloodPrefab = UnityEditor.AssetDatabase.LoadAssetAtPath<GameObject>("Assets/TJGeneratorLibEffects/Prefabs/Combat/Blood/Red/BloodExplosion.prefab");
}
#endif
if (bloodPrefab != null)
{
var vfx = Instantiate(bloodPrefab, position, Quaternion.identity);
vfx.transform.localScale = Vector3.one * 1.5f;
Destroy(vfx, 1.5f);
}
// 2. 红色抓痕
GameObject slashPrefab = clawSlashVfxPrefab;
#if UNITY_EDITOR
if (slashPrefab == null)
{
slashPrefab = UnityEditor.AssetDatabase.LoadAssetAtPath<GameObject>("Assets/TJGeneratorLibEffects/Prefabs/Combat/Sword/Slash/SwordSlashMini/SwordSlashMiniRed.prefab");
}
#endif
if (slashPrefab != null && unit != null)
{
Quaternion rot = Quaternion.Euler(-90f, 0f, -unit.transform.eulerAngles.y);
var vfx = Instantiate(slashPrefab, position, rot);
vfx.transform.localScale = Vector3.one * 1.4f;
Destroy(vfx, 1.0f);
}
}
private void OnSkillAnimationFinished()
{
if (isSkillPending)
{
ExecuteBiteStrike(); // 容错兜底:若动画结束仍未收到 Event,强制结算撕咬
}
}
private void OnDestroy()
{
WorldHealthBar.OnUnitKilled -= OnGlobalUnitKilled;
EndBloodthirst();
}
}