using System.Collections;
using System.Collections.Generic;
using UnityEngine;
///
/// 城堡法师技能:爆裂火球体系(1/3/6/10 级完整阶梯)
/// 1级【爆裂火球】:发射强力火球,对目标区域造成 140% 范围伤害(触发 MagicExplosionFire 爆破)
/// 3级【强化爆裂】:火球伤害提升至 175%,爆炸范围 +25%
/// 6级【灼烧火海】:爆裂处留下一片火海,对经过敌人造成 3 秒持续燃烧伤害
/// 10级【双发爆裂】:施法时连续轰出 2 颗爆裂火球,第二颗伤害提升 50% 且范围扩大
///
public class CastleMageSkill : UnitSkill
{
[Header("火球配置")]
[Tooltip("火球飞行速度")]
public float projectileSpeed = 16f;
[Tooltip("爆裂基础半径")]
public float baseExplosionRadius = 2.5f;
[Header("特效资源")]
public GameObject fireballMissilePrefab; // 火球飞弹 (FireballSharpMissileFire)
public GameObject explosionVfxPrefab; // 爆破特效 (MagicExplosionFire)
public GameObject burnFieldVfxPrefab; // 灼烧火海地面特效 (FireFieldRed)
private bool isSkillPending = false;
private void EnsureUnit()
{
if (unit == null)
{
unit = GetComponent();
}
}
///
/// 当能量蓄满时触发:播放法师技能施法动作
///
public override void ReleaseSkill()
{
EnsureUnit();
if (unit == null) return;
WorldHealthBar healthBar = unit.GetComponent();
if (healthBar == null || healthBar.IsDead) return;
if (unit.Target == null) return;
unit.FaceCurrentTarget(0f);
isSkillPending = true;
// 播放法师施法动作,由 OnSkillHit1 帧触发火球发射
unit.PlaySkillAnimation(OnSkillAnimationFinished, 1.8f);
Debug.Log($"城堡法师释放技能【爆裂火球】,等待 OnSkillHit1 施法帧!");
}
///
/// 动画命中帧方法:在法杖前挥法术成型的瞬间触发 (OnSkillHit1)
///
public void OnSkillHit1()
{
if (!isSkillPending) return;
isSkillPending = false;
EnsureUnit();
if (unit == null || unit.Target == null) return;
int level = unit.level;
// 1级 140%,3级+ 175%
float damageMultiplier = level >= 3 ? 1.75f : 1.40f;
float radius = level >= 3 ? baseExplosionRadius * 1.25f : baseExplosionRadius;
// 发射第一颗爆裂火球
LaunchFireball(unit.Target, damageMultiplier, radius, level >= 6);
// 10级大招【双发爆裂】:间隔 0.2 秒追加第二颗强化火球
if (level >= 10)
{
StartCoroutine(LaunchSecondFireballDelayed(unit.Target, damageMultiplier * 1.50f, radius * 1.30f, level >= 6));
}
Debug.Log($"【爆裂火球】发射! 伤害倍率: {damageMultiplier * 100:F0}%, 范围: {radius:F1}m (等级: {level})");
}
private IEnumerator LaunchSecondFireballDelayed(GameObject target, float damageMultiplier, float radius, bool createBurnField)
{
yield return new WaitForSeconds(0.25f);
if (target != null && target.activeInHierarchy && unit != null)
{
LaunchFireball(target, damageMultiplier, radius, createBurnField);
Debug.Log($"【双发爆裂】追加第二发火球! 伤害倍率: {damageMultiplier * 100:F0}%");
}
}
private void LaunchFireball(GameObject target, float damageMultiplier, float radius, bool createBurnField)
{
GameObject missilePrefab = fireballMissilePrefab;
if (missilePrefab == null && unit != null)
{
missilePrefab = unit.projectilePrefab;
}
#if UNITY_EDITOR
if (missilePrefab == null)
{
missilePrefab = UnityEditor.AssetDatabase.LoadAssetAtPath("Assets/TJGeneratorLibEffects/Prefabs/Combat/Missiles/FireballSharp/FireballSharpMissileFire.prefab");
}
#endif
if (missilePrefab == null || target == null || unit == null) return;
Vector3 spawnPos = unit.projectileSpawnPoint != null
? unit.projectileSpawnPoint.position
: unit.transform.position + Vector3.up * 1.2f + unit.transform.forward * 0.5f;
Vector3 dir = (target.transform.position - spawnPos).normalized;
GameObject missileGo = Instantiate(missilePrefab, spawnPos, Quaternion.LookRotation(dir));
float totalDamage = unit.attackPower * damageMultiplier;
// 使用自定义弧线/追踪脚本,并在命中时引发范围爆炸
var runner = missileGo.AddComponent();
runner.Initialize(target, totalDamage, radius, unit.gameObject, projectileSpeed, explosionVfxPrefab, burnFieldVfxPrefab, createBurnField);
}
private void OnSkillAnimationFinished()
{
isSkillPending = false;
}
}
///
/// 负责爆裂火球的飞行、落地爆炸伤害计算与灼烧火海生成
///
public class MageSkillFireballRunner : MonoBehaviour
{
private GameObject target;
private float damage;
private float explosionRadius;
private GameObject owner;
private float speed;
private GameObject explosionVfx;
private GameObject burnFieldVfx;
private bool createBurnField;
private bool hasExploded = false;
public void Initialize(GameObject targetObj, float dmg, float radius, GameObject ownerObj, float moveSpeed, GameObject expVfx, GameObject burnVfx, bool burnField)
{
target = targetObj;
damage = dmg;
explosionRadius = radius;
owner = ownerObj;
speed = moveSpeed;
explosionVfx = expVfx;
burnFieldVfx = burnVfx;
createBurnField = burnField;
// 屏蔽原有 Projectile,接管飞行与碰撞
var defaultProj = GetComponent();
if (defaultProj != null) defaultProj.enabled = false;
Destroy(gameObject, 4.0f);
}
private void Update()
{
if (hasExploded) return;
if (target == null)
{
ExplodeAtPosition(transform.position);
return;
}
Vector3 targetPos = target.transform.position + Vector3.up * 0.8f;
Vector3 toTarget = targetPos - transform.position;
float step = speed * Time.deltaTime;
if (toTarget.sqrMagnitude <= step * step || toTarget.sqrMagnitude <= 0.15f)
{
ExplodeAtPosition(targetPos);
return;
}
transform.rotation = Quaternion.LookRotation(toTarget.normalized);
transform.position += toTarget.normalized * step;
}
private void ExplodeAtPosition(Vector3 pos)
{
if (hasExploded) return;
hasExploded = true;
// 1. 生成爆炸视觉特效
GameObject expPrefab = explosionVfx;
#if UNITY_EDITOR
if (expPrefab == null)
{
expPrefab = UnityEditor.AssetDatabase.LoadAssetAtPath("Assets/TJGeneratorLibEffects/Prefabs/Combat/Explosions/MagicExplosion/MagicExplosionFire.prefab");
}
#endif
if (expPrefab != null)
{
var expGo = Instantiate(expPrefab, pos, Quaternion.identity);
expGo.transform.localScale = Vector3.one * (explosionRadius / 1.8f);
Destroy(expGo, 3.0f);
}
// 2. 结算范围伤害
ApplyAreaDamage(pos, explosionRadius, damage);
// 3. 6级解锁:生成持续 3 秒的灼烧火海(带有地面燃烧火焰特效)
if (createBurnField)
{
GameObject burnArea = new GameObject("BurnField");
burnArea.transform.position = new Vector3(pos.x, 0.05f, pos.z);
var area = burnArea.AddComponent();
GameObject fieldPrefab = burnFieldVfx;
#if UNITY_EDITOR
if (fieldPrefab == null)
{
fieldPrefab = UnityEditor.AssetDatabase.LoadAssetAtPath("Assets/TJGeneratorLibEffects/Prefabs/Environment/Fire/Cartoon/Field Intense/FireFieldIntenseRed.prefab");
}
#endif
area.Initialize(owner, damage * 0.15f, explosionRadius, 3.0f, fieldPrefab);
}
Destroy(gameObject);
}
private void ApplyAreaDamage(Vector3 center, float radius, float dmg)
{
if (owner == null) return;
UnitTeam myTeam = owner.GetComponent();
if (myTeam == null) return;
float sqrRadius = radius * radius;
var allUnits = Object.FindObjectsOfType();
foreach (var t in allUnits)
{
if (t == null || !t.gameObject.activeInHierarchy || !myTeam.IsEnemy(t.gameObject)) continue;
Vector3 flatOffset = t.transform.position - center;
flatOffset.y = 0f;
if (flatOffset.sqrMagnitude <= sqrRadius)
{
var targetUnit = t.GetComponentInParent();
if (targetUnit != null)
{
targetUnit.ReceiveDamage(dmg, owner);
}
else
{
var bar = t.GetComponentInParent();
if (bar != null) bar.TakeDamage(dmg, owner);
}
}
}
}
}
///
/// 6 级【灼烧火海】:在地面持续 3 秒,每秒对进入范围的敌人造成持续燃烧伤害
///
public class MageBurnArea : MonoBehaviour
{
private GameObject owner;
private float dps;
private float radius;
private float lifetime;
public void Initialize(GameObject ownerObj, float burnDps, float r, float duration, GameObject vfxPrefab)
{
owner = ownerObj;
dps = burnDps;
radius = r;
lifetime = duration;
// 实例化地面烈焰燃烧粒子特效(严格保持 X = -90° 旋转水平平铺地面)
if (vfxPrefab != null)
{
Quaternion rot = Quaternion.Euler(-90f, 0f, 0f);
var vfxInstance = Instantiate(vfxPrefab, transform.position, rot);
vfxInstance.transform.rotation = rot;
vfxInstance.transform.SetParent(transform, true);
vfxInstance.transform.localScale = Vector3.one * (radius / 1.5f);
}
StartCoroutine(BurnRoutine());
Destroy(gameObject, duration + 0.1f);
}
private IEnumerator BurnRoutine()
{
float timer = 0f;
float tickInterval = 0.5f;
while (timer < lifetime)
{
yield return new WaitForSeconds(tickInterval);
timer += tickInterval;
if (owner == null) break;
UnitTeam myTeam = owner.GetComponent();
if (myTeam == null) break;
float sqrRadius = radius * radius;
var allUnits = Object.FindObjectsOfType();
foreach (var t in allUnits)
{
if (t == null || !t.gameObject.activeInHierarchy || !myTeam.IsEnemy(t.gameObject)) continue;
Vector3 flatOffset = t.transform.position - transform.position;
flatOffset.y = 0f;
if (flatOffset.sqrMagnitude <= sqrRadius)
{
var unit = t.GetComponentInParent();
if (unit != null)
{
unit.ReceiveDamage(dps * tickInterval, owner);
}
else
{
var bar = t.GetComponentInParent();
if (bar != null) bar.TakeDamage(dps * tickInterval, owner);
}
}
}
}
}
}