Files
daluandou/Assets/Scripts/技能脚本/PlayerSkillSystem.cs
T
huadexuan 8534d974a9 ```
feat(PlayerSkillSystem): 实现天雷狂轰技能特效和伤害机制

- 添加技能2特效配置,包括落雷击中特效和雷暴全屏光环特效
- 更新技能2名称从"全屏AOE伤害"为"全屏天雷狂轰伤害"
- 实现屏幕中央触发全屏雷暴光环效果
- 添加交错落雷机制,对敌方单位进行精确打击
- 支持无敌人时在敌方阵地随机散落震撼天雷
- 优化伤害计算和冷却逻辑
- 同步更新技能日志信息和代码注释
```
2026-10-08 00:08:46 +08:00

402 lines
13 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 UnityEngine;
using UnityEngine.UI;
/// <summary>
/// 玩家技能系统(召唤师技能)
/// 管理技能释放和冷却
/// </summary>
public class PlayerSkillSystem : MonoBehaviour
{
public static PlayerSkillSystem Instance { get; private set; }
[Header("战术增益加成倍率")]
public float cooldownMultiplier = 1f; // 冷却缩减倍率 (如 0.9 = CD 缩减 10%)
public float powerMultiplier = 1f; // 威力加成倍率 (如 1.15 = 效果提升 15%)
[Header("技能1:群体治疗")]
public Button skill1Button;
public Text skill1CooldownText;
public float skill1Cooldown = 20f;
public float skill1HealAmount = 100f;
private float skill1RemainingCooldown = 0f;
[Header("技能1特效配置")]
public GameObject cureBallPrefab; // 飞球预制体 (Assets/Prefabs/特效/飞球/cureBall.prefab)
public GameObject healNovaPrefab; // 治疗冲击波预制体 (Assets/TJGeneratorLibEffects/Prefabs/Interactive/Healing/HealNova.prefab)
public Transform castStartTransform; // 技能施放起点 (如未指定默认摄像机下方或召唤师位置)
public Vector3 castTargetPosition = new Vector3(0f, 0.1f, -9f); // 我方阵地中心落地点
[Header("技能2:全屏AOE")]
public Button skill2Button;
public Text skill2CooldownText;
public float skill2Cooldown = 20f;
public float skill2Damage = 80f;
private float skill2RemainingCooldown = 0f;
[Header("技能2特效配置")]
public GameObject lightningStrikePrefab; // 落雷击中特效 (Assets/TJGeneratorLibEffects/Prefabs/Combat/Explosions/LightningExplosion/LightningExplosionBlue.prefab)
public GameObject lightningNovaPrefab; // 雷暴全屏光环特效 (Assets/TJGeneratorLibEffects/Prefabs/Combat/Nova/Lightning/NovaLightningBlue.prefab)
private void Awake()
{
Instance = this;
}
private void Start()
{
// 自动从场景或父节点绑定技能按钮与图标引用
EnsureSkillUIReferences();
// 从 PlayerData 加载玩家装备的 2 个召唤师技能图标
LoadEquippedSkillIcons();
// 绑定按钮点击事件
if (skill1Button != null)
{
skill1Button.onClick.AddListener(UseSkill1);
}
if (skill2Button != null)
{
skill2Button.onClick.AddListener(UseSkill2);
}
}
private void EnsureSkillUIReferences()
{
var canvas = GameObject.Find("TowerDefenseCanvas");
if (canvas == null) return;
var skillsPanel = canvas.transform.Find("BottomUI/SkillsPanel");
if (skillsPanel == null) return;
if (skill1Button == null && skillsPanel.childCount > 0)
{
var item1 = skillsPanel.GetChild(0);
skill1Button = item1.GetComponent<Button>();
if (skill1Button == null) skill1Button = item1.gameObject.AddComponent<Button>();
}
if (skill2Button == null && skillsPanel.childCount > 1)
{
var item2 = skillsPanel.GetChild(1);
skill2Button = item2.GetComponent<Button>();
if (skill2Button == null) skill2Button = item2.gameObject.AddComponent<Button>();
}
}
/// <summary>
/// 从 PlayerData 读取玩家配置的 2 个召唤师技能名称,并绑定图标到 UI 位置
/// </summary>
public void LoadEquippedSkillIcons()
{
string skill1Name = "神圣赞歌";
string skill2Name = "陨石轰炸";
if (PlayerDataManager.Instance != null && PlayerDataManager.Instance.equippedSummonerSkills != null && PlayerDataManager.Instance.equippedSummonerSkills.Length >= 2)
{
skill1Name = PlayerDataManager.Instance.equippedSummonerSkills[0];
skill2Name = PlayerDataManager.Instance.equippedSummonerSkills[1];
}
SetSkillIcon(skill1Button, skill1Name);
SetSkillIcon(skill2Button, skill2Name);
}
private void SetSkillIcon(Button skillBtn, string skillName)
{
if (skillBtn == null || string.IsNullOrEmpty(skillName)) return;
Image img = skillBtn.GetComponent<Image>();
if (img != null)
{
Sprite icon = GetSkillIconSprite(skillName);
if (icon != null)
{
img.sprite = icon;
}
}
}
public static Sprite GetSkillIconSprite(string skillName)
{
if (string.IsNullOrEmpty(skillName)) return null;
Sprite icon = Resources.Load<Sprite>($"Picture/UI/召唤师技能图标/{skillName}");
#if UNITY_EDITOR
if (icon == null)
{
icon = UnityEditor.AssetDatabase.LoadAssetAtPath<Sprite>($"Assets/Picture/UI/召唤师技能图标/{skillName}.png");
}
#endif
return icon;
}
private void Update()
{
// 更新技能1冷却
if (skill1RemainingCooldown > 0)
{
skill1RemainingCooldown -= Time.deltaTime;
if (skill1Button != null)
{
skill1Button.interactable = false;
}
if (skill1CooldownText != null)
{
skill1CooldownText.text = Mathf.CeilToInt(skill1RemainingCooldown).ToString();
skill1CooldownText.gameObject.SetActive(true);
}
}
else
{
if (skill1Button != null)
{
skill1Button.interactable = true;
}
if (skill1CooldownText != null)
{
skill1CooldownText.gameObject.SetActive(false);
}
}
// 更新技能2冷却
if (skill2RemainingCooldown > 0)
{
skill2RemainingCooldown -= Time.deltaTime;
if (skill2Button != null)
{
skill2Button.interactable = false;
}
if (skill2CooldownText != null)
{
skill2CooldownText.text = Mathf.CeilToInt(skill2RemainingCooldown).ToString();
skill2CooldownText.gameObject.SetActive(true);
}
}
else
{
if (skill2Button != null)
{
skill2Button.interactable = true;
}
if (skill2CooldownText != null)
{
skill2CooldownText.gameObject.SetActive(false);
}
}
}
/// <summary>
/// 使用技能1:群体治疗
/// </summary>
public void UseSkill1()
{
if (skill1RemainingCooldown > 0)
{
return;
}
float finalHeal = skill1HealAmount * powerMultiplier;
Debug.Log($"释放技能1:群体治疗(恢复 {finalHeal:F1} 生命,威力倍率: {powerMultiplier:F2})");
// 智能获取友方阵地中心或平均位置
Vector3 targetPos = GetAllyCenterPosition();
Vector3 startPos = castStartTransform != null ? castStartTransform.position : new Vector3(targetPos.x, targetPos.y + 10f, targetPos.z - 8f);
// 加载/实例化抛物线 cureBall
GameObject ballPrefab = cureBallPrefab;
if (ballPrefab == null)
{
ballPrefab = Resources.Load<GameObject>("Prefabs/特效/飞球/cureBall");
}
#if UNITY_EDITOR
if (ballPrefab == null)
{
ballPrefab = UnityEditor.AssetDatabase.LoadAssetAtPath<GameObject>("Assets/Prefabs/特效/飞球/cureBall.prefab");
}
#endif
GameObject novaPrefab = healNovaPrefab;
#if UNITY_EDITOR
if (novaPrefab == null)
{
novaPrefab = UnityEditor.AssetDatabase.LoadAssetAtPath<GameObject>("Assets/TJGeneratorLibEffects/Prefabs/Interactive/Healing/HealNova.prefab");
}
#endif
if (ballPrefab != null)
{
GameObject ballGo = Instantiate(ballPrefab, startPos, Quaternion.identity);
var parabola = ballGo.GetComponent<ParabolaFlyObject>();
if (parabola == null)
{
parabola = ballGo.AddComponent<ParabolaFlyObject>();
}
parabola.Launch(startPos, targetPos, 0.8f, 4.5f, novaPrefab, () =>
{
// 对所有友方单位施加治疗
BuffSystem.Instance.ApplyGroupHeal(finalHeal);
});
}
else
{
// 特效缺失兜底直接治疗
BuffSystem.Instance.ApplyGroupHeal(finalHeal);
}
// 开始冷却
skill1RemainingCooldown = skill1Cooldown * cooldownMultiplier;
}
/// <summary>
/// 计算场上己方英雄的实时中心点位置,无单位时回退默认网格中心
/// </summary>
private Vector3 GetAllyCenterPosition()
{
var heroes = FindObjectsOfType<UnitBase>();
Vector3 sumPos = Vector3.zero;
int count = 0;
foreach (var hero in heroes)
{
if (hero == null || !hero.gameObject.activeInHierarchy) continue;
UnitTeam team = hero.GetComponent<UnitTeam>();
if (team != null && team.IsLocalPlayerTeam())
{
sumPos += hero.transform.position;
count++;
}
}
if (count > 0)
{
Vector3 center = sumPos / count;
center.y = 0.1f;
return center;
}
return new Vector3(0f, 0.1f, -10f); // 网格阵地真正中心点
}
/// <summary>
/// 使用技能2:全屏天雷狂轰伤害
/// </summary>
public void UseSkill2()
{
if (skill2RemainingCooldown > 0)
{
return;
}
float finalDamage = skill2Damage * powerMultiplier;
Debug.Log($"释放技能2:天雷狂轰(造成 {finalDamage:F1} 伤害,威力倍率: {powerMultiplier:F2})");
// 加载特效资源
GameObject strikePrefab = lightningStrikePrefab;
#if UNITY_EDITOR
if (strikePrefab == null)
{
strikePrefab = UnityEditor.AssetDatabase.LoadAssetAtPath<GameObject>("Assets/TJGeneratorLibEffects/Prefabs/Combat/Explosions/LightningExplosion/LightningExplosionBlue.prefab");
}
#endif
GameObject novaPrefab = lightningNovaPrefab;
#if UNITY_EDITOR
if (novaPrefab == null)
{
novaPrefab = UnityEditor.AssetDatabase.LoadAssetAtPath<GameObject>("Assets/TJGeneratorLibEffects/Prefabs/Combat/Nova/Lightning/NovaLightningBlue.prefab");
}
#endif
// 1. 屏幕中央触发全屏雷暴光环
if (novaPrefab != null)
{
Vector3 centerPos = new Vector3(0f, 0.1f, 0f);
var novaGo = Instantiate(novaPrefab, centerPos, novaPrefab.transform.rotation);
Destroy(novaGo, 3.5f);
}
// 2. 检索所有活着的敌方单位
var allUnits = FindObjectsOfType<UnitBase>();
var targetEnemies = new System.Collections.Generic.List<UnitBase>();
foreach (var unit in allUnits)
{
if (unit == null || !unit.gameObject.activeInHierarchy) continue;
var team = unit.GetComponent<UnitTeam>();
if (team != null && team.teamId == 1) // 敌方
{
var healthBar = unit.GetComponent<WorldHealthBar>();
if (healthBar != null && !healthBar.IsDead)
{
targetEnemies.Add(unit);
}
}
}
StartCoroutine(ExecuteLightningStrikesRoutine(targetEnemies, strikePrefab, finalDamage));
// 开始冷却
skill2RemainingCooldown = skill2Cooldown * cooldownMultiplier;
}
private System.Collections.IEnumerator ExecuteLightningStrikesRoutine(
System.Collections.Generic.List<UnitBase> targetEnemies,
GameObject strikePrefab,
float finalDamage)
{
if (targetEnemies.Count > 0)
{
// 敌群交错落雷
for (int i = 0; i < targetEnemies.Count; i++)
{
var enemy = targetEnemies[i];
if (enemy != null && enemy.gameObject.activeInHierarchy)
{
Vector3 strikePos = enemy.transform.position;
strikePos.y = 0.1f;
if (strikePrefab != null)
{
var strikeGo = Instantiate(strikePrefab, strikePos, strikePrefab.transform.rotation);
Destroy(strikeGo, 3f);
}
var healthBar = enemy.GetComponent<WorldHealthBar>();
if (healthBar != null && !healthBar.IsDead)
{
healthBar.TakeDamage(finalDamage);
}
}
yield return new WaitForSeconds(0.08f); // 80毫秒交错落雷节奏
}
}
else
{
// 无敌人时在敌方阵地随机散落 6 道震撼天雷
for (int i = 0; i < 6; i++)
{
Vector3 randomPos = new Vector3(Random.Range(-5f, 5f), 0.1f, Random.Range(2f, 12f));
if (strikePrefab != null)
{
var strikeGo = Instantiate(strikePrefab, randomPos, strikePrefab.transform.rotation);
Destroy(strikeGo, 3f);
}
yield return new WaitForSeconds(0.08f);
}
}
}
/// <summary>
/// 重置所有技能冷却(测试用)
/// </summary>
public void ResetAllCooldowns()
{
skill1RemainingCooldown = 0f;
skill2RemainingCooldown = 0f;
}
}