根据提供的code differences信息,由于没有具体的代码变更内容,我将生成一个通用的commit message模板:

```
docs(readme): 更新文档说明

- 添加项目使用指南
- 完善API接口说明
- 修正错误的配置示例
```

注意:由于您提供的code differences部分为空,以上是一个示例模板。当您有具体的代码变更时,请提供详细的变更内容以便生成更准确的commit message。
This commit is contained in:
huadexuan committed 2026-10-12 18:06:46 +08:00
1 parent f6f6666244
commit ec35c6c154
35 files changed
+54920 -311

No files matched your search

+311 -28
View File
@@ -1,49 +1,332 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 城堡法师技能:爆裂火球体系(1/3/6/10 级完整阶梯)
/// 1级【爆裂火球】:发射强力火球,对目标区域造成 140% 范围伤害(触发 MagicExplosionFire 爆破)
/// 3级【强化爆裂】:火球伤害提升至 175%,爆炸范围 +25%
/// 6级【灼烧火海】:爆裂处留下一片火海,对经过敌人造成 3 秒持续燃烧伤害
/// 10级【双发爆裂】:施法时连续轰出 2 颗爆裂火球,第二颗伤害提升 50% 且范围扩大
/// </summary>
public class CastleMageSkill : UnitSkill
{
[Header("小型魔爆参数")]
[Min(0.1f)]
public float explosionRadius = 1.8f;
[Header("火球配置")]
[Tooltip("火球飞行速度")]
public float projectileSpeed = 16f;
[Min(0f)]
public float explosionDamage = 85f;
[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<UnitBase>();
}
}
/// <summary>
/// 当能量蓄满时触发:播放法师技能施法动作
/// </summary>
public override void ReleaseSkill()
{
GameObject target = unit.Target;
UnitTeam myTeam = unit.GetComponent<UnitTeam>();
if (target == null || myTeam == null)
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;
// 播放法师施法动作,由 OnSkillHit1 帧触发火球发射
unit.PlaySkillAnimation(OnSkillAnimationFinished, 1.8f);
Debug.Log($"<color=orange>城堡法师释放技能【爆裂火球】</color>,等待 OnSkillHit1 施法帧!");
}
/// <summary>
/// 动画命中帧方法:在法杖前挥法术成型的瞬间触发 (OnSkillHit1)
/// </summary>
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($"<color=orange>【爆裂火球】发射!</color> 伤害倍率: {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($"<color=red>【双发爆裂】追加第二发火球!</color> 伤害倍率: {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<GameObject>("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<MageSkillFireballRunner>();
runner.Initialize(target, totalDamage, radius, unit.gameObject, projectileSpeed, explosionVfxPrefab, burnFieldVfxPrefab, createBurnField);
}
private void OnSkillAnimationFinished()
{
isSkillPending = false;
}
}
/// <summary>
/// 负责爆裂火球的飞行、落地爆炸伤害计算与灼烧火海生成
/// </summary>
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<Projectile>();
if (defaultProj != null) defaultProj.enabled = false;
Destroy(gameObject, 4.0f);
}
private void Update()
{
if (hasExploded) return;
if (target == null)
{
ExplodeAtPosition(transform.position);
return;
}
Vector3 center = target.transform.position;
float radiusSquared = explosionRadius * explosionRadius;
HashSet<UnitBase> hitUnits = new HashSet<UnitBase>();
Vector3 targetPos = target.transform.position + Vector3.up * 0.8f;
Vector3 toTarget = targetPos - transform.position;
float step = speed * Time.deltaTime;
foreach (UnitTeam opponentTeam in GameObject.FindObjectsOfType<UnitTeam>())
if (toTarget.sqrMagnitude <= step * step || toTarget.sqrMagnitude <= 0.15f)
{
GameObject opponent = opponentTeam.gameObject;
if (opponent == null
|| opponent.transform.root == unit.transform.root
|| !myTeam.IsEnemy(opponent))
{
continue;
}
ExplodeAtPosition(targetPos);
return;
}
Vector3 offset = opponent.transform.position - center;
offset.y = 0f;
if (offset.sqrMagnitude > radiusSquared)
{
continue;
}
transform.rotation = Quaternion.LookRotation(toTarget.normalized);
transform.position += toTarget.normalized * step;
}
UnitBase targetUnit = opponent.GetComponentInParent<UnitBase>();
if (targetUnit != null && hitUnits.Add(targetUnit))
private void ExplodeAtPosition(Vector3 pos)
{
if (hasExploded) return;
hasExploded = true;
// 1. 生成爆炸视觉特效
GameObject expPrefab = explosionVfx;
#if UNITY_EDITOR
if (expPrefab == null)
{
expPrefab = UnityEditor.AssetDatabase.LoadAssetAtPath<GameObject>("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<MageBurnArea>();
GameObject fieldPrefab = burnFieldVfx;
#if UNITY_EDITOR
if (fieldPrefab == null)
{
targetUnit.ReceiveDamage(explosionDamage, unit.gameObject);
fieldPrefab = UnityEditor.AssetDatabase.LoadAssetAtPath<GameObject>("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<UnitTeam>();
if (myTeam == null) return;
float sqrRadius = radius * radius;
var allUnits = Object.FindObjectsOfType<UnitTeam>();
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<UnitBase>();
if (targetUnit != null)
{
targetUnit.ReceiveDamage(dmg, owner);
}
else
{
var bar = t.GetComponentInParent<WorldHealthBar>();
if (bar != null) bar.TakeDamage(dmg, owner);
}
}
}
}
}
/// <summary>
/// 6 级【灼烧火海】:在地面持续 3 秒,每秒对进入范围的敌人造成持续燃烧伤害
/// </summary>
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<UnitTeam>();
if (myTeam == null) break;
float sqrRadius = radius * radius;
var allUnits = Object.FindObjectsOfType<UnitTeam>();
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<UnitBase>();
if (unit != null)
{
unit.ReceiveDamage(dps * tickInterval, owner);
}
else
{
var bar = t.GetComponentInParent<WorldHealthBar>();
if (bar != null) bar.TakeDamage(dps * tickInterval, owner);
}
}
}
}
}