``` docs(readme): 更新文档说明 - 添加项目使用指南 - 完善API接口说明 - 修正错误的配置示例 ``` 注意:由于您提供的code differences部分为空,以上是一个示例模板。当您有具体的代码变更时,请提供详细的变更内容以便生成更准确的commit message。
388 lines
10 KiB
C#
388 lines
10 KiB
C#
using UnityEngine;
|
|
using UnityEngine.UI;
|
|
|
|
/// <summary>
|
|
/// 英雄卡片UI控制
|
|
/// 显示英雄状态、血条、死亡倒计时、复活按钮
|
|
/// </summary>
|
|
public class HeroCardUI : MonoBehaviour
|
|
{
|
|
[Header("引用")]
|
|
public Image iconImage; // 英雄头像
|
|
public Image rarityFrameImage; // 稀有度边框
|
|
public Sprite blueRarityFrame;
|
|
public Sprite orangeRarityFrame;
|
|
public Sprite purpleRarityFrame;
|
|
public Sprite redRarityFrame;
|
|
public Image hpFillImage; // 血条填充
|
|
public GameObject deathPanel; // 死亡遮罩
|
|
public Text reviveTimerText; // 复活倒计时文本
|
|
public Button reviveButton; // 立即复活按钮(看广告)
|
|
public Text reviveCountText; // 剩余复活次数
|
|
|
|
[Header("绑定的英雄")]
|
|
public UnitBase heroUnit; // 关联的英雄单位
|
|
private WorldHealthBar heroHealthBar;
|
|
private Vector3 heroSpawnPosition; // 英雄出生位置
|
|
|
|
[Header("复活设置")]
|
|
public float reviveTime = 20f; // 自动复活时间
|
|
private float reviveTimer = 0f;
|
|
private bool isDead = false;
|
|
|
|
[Header("广告复活次数")]
|
|
public int maxAdRevives = 2; // 每局最多2次
|
|
private int remainingAdRevives = 2;
|
|
|
|
private void Start()
|
|
{
|
|
// 初始化复活次数
|
|
remainingAdRevives = maxAdRevives;
|
|
UpdateReviveCountUI();
|
|
|
|
// 绑定复活按钮
|
|
if (reviveButton != null)
|
|
{
|
|
reviveButton.onClick.AddListener(OnReviveButtonClicked);
|
|
}
|
|
|
|
// 默认隐藏死亡面板
|
|
if (deathPanel != null)
|
|
{
|
|
deathPanel.SetActive(false);
|
|
}
|
|
}
|
|
|
|
private void Update()
|
|
{
|
|
if (heroUnit == null || heroHealthBar == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// 更新血条
|
|
UpdateHealthBar();
|
|
|
|
// 检查死亡状态
|
|
if (heroHealthBar.IsDead && !isDead)
|
|
{
|
|
OnHeroDeath();
|
|
}
|
|
|
|
// 检查是否已复活(外部复活,例如通过其他系统)
|
|
if (isDead && !heroHealthBar.IsDead && heroUnit.gameObject.activeSelf)
|
|
{
|
|
// 已复活,重置UI状态
|
|
isDead = false;
|
|
if (deathPanel != null)
|
|
{
|
|
deathPanel.SetActive(false);
|
|
}
|
|
}
|
|
|
|
// 更新复活倒计时
|
|
if (isDead)
|
|
{
|
|
UpdateReviveTimer();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 设置英雄单位
|
|
/// </summary>
|
|
public void SetHero(UnitBase unit, Sprite icon, Vector3 spawnPos)
|
|
{
|
|
SetHero(unit, icon, spawnPos, null);
|
|
}
|
|
|
|
public void SetHero(UnitBase unit, Sprite icon, Vector3 spawnPos, CharacterData characterData)
|
|
{
|
|
heroUnit = unit;
|
|
heroSpawnPosition = spawnPos;
|
|
|
|
if (unit != null)
|
|
{
|
|
heroHealthBar = unit.GetComponent<WorldHealthBar>();
|
|
}
|
|
|
|
if (iconImage != null && icon != null)
|
|
{
|
|
iconImage.sprite = icon;
|
|
}
|
|
|
|
UpdateRarityFrame(characterData);
|
|
UpdateCharacterName(characterData);
|
|
|
|
isDead = false;
|
|
if (deathPanel != null)
|
|
{
|
|
deathPanel.SetActive(false);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 只刷新卡面(头像 / 名字 / 稀有度边框),不绑定单位。
|
|
/// 布阵阶段按玩家出战阵容初始化卡片时用,避免"卡片显示 A、拖出来却是 B"。
|
|
/// </summary>
|
|
public void SetCharacterInfo(CharacterData characterData)
|
|
{
|
|
if (characterData == null) return;
|
|
|
|
if (iconImage != null && characterData.cardIcon != null)
|
|
{
|
|
iconImage.sprite = characterData.cardIcon;
|
|
}
|
|
|
|
UpdateRarityFrame(characterData);
|
|
UpdateCharacterName(characterData);
|
|
}
|
|
|
|
private void UpdateRarityFrame(CharacterData characterData)
|
|
{
|
|
if (rarityFrameImage == null)
|
|
{
|
|
Transform frame = transform.Find("RarityFrame") ?? transform.Find("稀有度边框");
|
|
if (frame != null)
|
|
{
|
|
rarityFrameImage = frame.GetComponent<Image>();
|
|
}
|
|
}
|
|
|
|
if (rarityFrameImage == null || characterData == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
Sprite frameSprite = characterData.rarity switch
|
|
{
|
|
CharacterRarity.Blue => blueRarityFrame,
|
|
CharacterRarity.Orange => orangeRarityFrame,
|
|
CharacterRarity.Purple => purpleRarityFrame,
|
|
CharacterRarity.Red => redRarityFrame,
|
|
_ => blueRarityFrame
|
|
};
|
|
|
|
if (frameSprite != null)
|
|
{
|
|
rarityFrameImage.sprite = frameSprite;
|
|
}
|
|
}
|
|
|
|
private void UpdateCharacterName(CharacterData characterData)
|
|
{
|
|
if (characterData == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// 查找 NameLabel/Text
|
|
Transform nameLabel = transform.Find("NameLabel");
|
|
if (nameLabel != null)
|
|
{
|
|
Transform textTransform = nameLabel.Find("Text");
|
|
if (textTransform != null)
|
|
{
|
|
Text nameText = textTransform.GetComponent<Text>();
|
|
if (nameText != null)
|
|
{
|
|
nameText.text = characterData.characterName;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 更新血条显示
|
|
/// </summary>
|
|
private void UpdateHealthBar()
|
|
{
|
|
if (hpFillImage != null && heroHealthBar != null)
|
|
{
|
|
float fillAmount = heroHealthBar.maxHealth > 0
|
|
? heroHealthBar.currentHealth / heroHealthBar.maxHealth
|
|
: 0f;
|
|
hpFillImage.fillAmount = fillAmount;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 英雄死亡
|
|
/// </summary>
|
|
private void OnHeroDeath()
|
|
{
|
|
isDead = true;
|
|
reviveTimer = reviveTime;
|
|
|
|
// 显示死亡面板
|
|
if (deathPanel != null)
|
|
{
|
|
deathPanel.SetActive(true);
|
|
}
|
|
|
|
// 更新复活按钮状态
|
|
UpdateReviveButton();
|
|
|
|
// 阻止英雄单位被销毁(取消延迟销毁)
|
|
if (heroUnit != null)
|
|
{
|
|
// 取消所有Destroy调用
|
|
CancelInvoke();
|
|
}
|
|
|
|
Debug.Log($"英雄 {heroUnit.name} 死亡,{reviveTime}秒后复活");
|
|
}
|
|
|
|
/// <summary>
|
|
/// 更新复活倒计时
|
|
/// </summary>
|
|
private void UpdateReviveTimer()
|
|
{
|
|
reviveTimer -= Time.deltaTime;
|
|
|
|
// 更新倒计时文本
|
|
if (reviveTimerText != null)
|
|
{
|
|
reviveTimerText.text = Mathf.CeilToInt(reviveTimer).ToString() + "s";
|
|
}
|
|
|
|
// 时间到,自动复活
|
|
if (reviveTimer <= 0f)
|
|
{
|
|
ReviveHero();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 复活英雄
|
|
/// </summary>
|
|
private void ReviveHero()
|
|
{
|
|
if (heroUnit == null || heroHealthBar == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// 重新激活GameObject(必须先激活,否则无法操作组件)
|
|
heroUnit.gameObject.SetActive(true);
|
|
|
|
// 重新启用渲染器
|
|
foreach (Renderer renderer in heroUnit.GetComponentsInChildren<Renderer>())
|
|
{
|
|
renderer.enabled = true;
|
|
}
|
|
|
|
// 移动到出生位置
|
|
heroUnit.transform.position = heroSpawnPosition;
|
|
|
|
// 重置 NavMeshAgent
|
|
var navAgent = heroUnit.GetComponent<UnityEngine.AI.NavMeshAgent>();
|
|
if (navAgent != null)
|
|
{
|
|
navAgent.enabled = true; // 确保启用
|
|
if (!navAgent.isOnNavMesh)
|
|
{
|
|
navAgent.enabled = false;
|
|
navAgent.enabled = true;
|
|
}
|
|
navAgent.ResetPath(); // 清空旧路径
|
|
}
|
|
|
|
// 重置 UnitBase 状态(关键修复:清空目标让单位重新寻敌)
|
|
UnitBase unitBase = heroUnit.GetComponent<UnitBase>();
|
|
if (unitBase != null)
|
|
{
|
|
unitBase.enabled = true; // 确保脚本启用
|
|
unitBase.target = null; // 清空目标
|
|
unitBase.ResetAnchorPosition(); // 重置锚点位置到复活位置(修复一直尝试返回旧锚点的问题)
|
|
}
|
|
|
|
// 重置 Animator
|
|
Animator animator = heroUnit.GetComponent<Animator>();
|
|
if (animator != null)
|
|
{
|
|
animator.enabled = true;
|
|
animator.Rebind(); // 重置动画状态
|
|
animator.Update(0f);
|
|
}
|
|
|
|
// 使用WorldHealthBar的Revive方法(会重置isDead并恢复生命)
|
|
heroHealthBar.Revive(heroHealthBar.maxHealth);
|
|
|
|
// 重新显示血条(修复复活后没有血条的问题)
|
|
Transform barTransform = heroHealthBar.transform.Find("WorldHealthBar");
|
|
if (barTransform != null)
|
|
{
|
|
barTransform.gameObject.SetActive(true);
|
|
}
|
|
|
|
// 重置UI状态
|
|
isDead = false;
|
|
if (deathPanel != null)
|
|
{
|
|
deathPanel.SetActive(false);
|
|
}
|
|
|
|
Debug.Log($"HeroCardUI: {heroUnit.name} 复活完成");
|
|
}
|
|
|
|
/// <summary>
|
|
/// 点击立即复活按钮(看广告)
|
|
/// </summary>
|
|
private void OnReviveButtonClicked()
|
|
{
|
|
if (remainingAdRevives <= 0)
|
|
{
|
|
Debug.LogWarning("本局广告复活次数已用完");
|
|
return;
|
|
}
|
|
|
|
if (!isDead)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// TODO: 播放广告
|
|
Debug.Log("播放广告...");
|
|
|
|
// 扣除复活次数
|
|
remainingAdRevives--;
|
|
UpdateReviveCountUI();
|
|
|
|
// 立即复活
|
|
ReviveHero();
|
|
}
|
|
|
|
/// <summary>
|
|
/// 更新复活按钮状态
|
|
/// </summary>
|
|
private void UpdateReviveButton()
|
|
{
|
|
if (reviveButton != null)
|
|
{
|
|
reviveButton.interactable = remainingAdRevives > 0;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 更新剩余复活次数UI
|
|
/// </summary>
|
|
private void UpdateReviveCountUI()
|
|
{
|
|
if (reviveCountText != null)
|
|
{
|
|
reviveCountText.text = $"复活 {remainingAdRevives}/{maxAdRevives}";
|
|
}
|
|
|
|
UpdateReviveButton();
|
|
}
|
|
|
|
/// <summary>
|
|
/// 重置复活次数(新局开始时调用)
|
|
/// </summary>
|
|
public void ResetReviveCount()
|
|
{
|
|
remainingAdRevives = maxAdRevives;
|
|
UpdateReviveCountUI();
|
|
}
|
|
}
|