TH1/Unity/Assets/Scripts/TH1_Renderer/UnitStatusArea.cs
2026-06-27 02:30:03 +08:00

310 lines
12 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.Generic;
using Logic.Skill;
using RuntimeData;
using TH1_Logic.Core;
using UnityEngine;
namespace TH1_Renderer
{
internal class UnitStatusIcon
{
public int Level;
public StatusIconMono IconMono;
public GameObject IconObject;
}
/// <summary>
/// 单位状态管理器 - 管理单位的所有重要负面状态显示
/// </summary>
public class UnitStatusArea
{
private readonly Dictionary<SkillType, UnitStatusIcon> _statusIcons = new();
private readonly Dictionary<SkillType, int> _statusLevels = new();
private readonly Transform _statusContainer;
private readonly GameObject _statusIconPrefab;
private readonly UnityEngine.RectTransform _infoGroup;
// private const string KOMEIJI_FEAR_PATH = "TH1UI/Icon/SkillIcon/Komeiji/Skill_KomeijiFear";
// private const string KOMEIJI_FEAR2_PATH = "TH1UI/Icon/SkillIcon/Komeiji/Skill_KomeijiFear2";
/// <summary>
/// 当前显示的状态数量
/// </summary>
public int Count => _statusIcons.Count;
/// <summary>
/// 获取所有当前显示的状态
/// </summary>
internal IEnumerable<UnitStatusIcon> AllIcons => _statusIcons.Values;
public UnitStatusArea(Transform statusContainer, GameObject statusIconPrefab, UnityEngine.RectTransform infoGroup = null)
{
_statusContainer = statusContainer;
_statusIconPrefab = statusIconPrefab;
_infoGroup = infoGroup;
}
/// <summary>
/// 添加或更新状态显示
/// </summary>
/// <param name="skillType">技能类型</param>
/// <param name="unitFullType">单位完整类型</param>
/// <param name="hasLevel">是否有层数机制</param>
/// <param name="level">技能等级/层数</param>
/// <returns>是否成功添加或更新</returns>
public bool AddOrUpdateStatus(SkillType skillType, UnitFullType unitFullType, bool hasLevel, int level)
{
if (_statusIconPrefab == null || _statusContainer == null)
return false;
if (!_statusIcons.TryGetValue(skillType, out var existingIcon))
{
var newIconObj = GameObject.Instantiate(_statusIconPrefab, _statusContainer);
var iconMono = newIconObj.GetComponent<StatusIconMono>();
if (iconMono == null)
{
iconMono = newIconObj.AddComponent<StatusIconMono>();
}
existingIcon = new UnitStatusIcon
{
IconObject = newIconObj,
IconMono = iconMono,
Level = 0
};
_statusIcons.Add(skillType, existingIcon);
}
existingIcon.Level = level;
existingIcon.IconMono.SetContent(skillType, unitFullType, hasLevel, level);
// if (skillType == SkillType.KomeijiFear)
// {
// string targetPath = level >= 2 ? KOMEIJI_FEAR2_PATH : KOMEIJI_FEAR_PATH;
// var specialSprite = TH1Resource.ResourceLoader.Load<Sprite>(targetPath);
// if (specialSprite != null)
// {
// existingIcon.IconMono.SetIcon(specialSprite);
// }
// existingIcon.IconMono.SetColor(Color.green);
// }
// else
// {
// existingIcon.IconMono.SetColor(Color.white);
// }
existingIcon.IconMono.SetColor(Color.white);
_statusLevels[skillType] = level;
RefreshLayout();
return true;
}
/// <summary>
/// 移除指定状态
/// </summary>
/// <param name="skillType">技能类型</param>
/// <returns>是否成功移除</returns>
public bool RemoveStatus(SkillType skillType)
{
if (!_statusIcons.TryGetValue(skillType, out var icon))
return false;
if (icon.IconObject != null)
{
// GameObject.Destroy 是延迟销毁;先 SetActive(false) 让 LayoutGroup 在本帧
// 重建时立即忽略此节点,否则 StatusAreaContainer 的尺寸测量仍会包含它,
// 导致父节点InfoGroup/背景板)的尺寸无法收缩。
icon.IconObject.SetActive(false);
GameObject.Destroy(icon.IconObject);
}
_statusIcons.Remove(skillType);
_statusLevels.Remove(skillType);
// 移除后强制刷新布局
RefreshLayout();
return true;
}
/// <summary>
/// 检查是否包含指定状态
/// </summary>
public bool HasStatus(SkillType skillType)
{
return _statusIcons.ContainsKey(skillType);
}
/// <summary>
/// 获取指定状态的层数
/// </summary>
public int GetStatusLevel(SkillType skillType)
{
return _statusLevels.TryGetValue(skillType, out var level) ? level : 0;
}
/// <summary>
/// 清除所有状态
/// </summary>
public void ClearAllStatus()
{
foreach (var icon in _statusIcons.Values)
{
if (icon.IconObject != null)
{
// 先 SetActive(false) 让 LayoutGroup 立即忽略,再 Destroy延迟销毁
icon.IconObject.SetActive(false);
GameObject.Destroy(icon.IconObject);
}
}
_statusIcons.Clear();
_statusLevels.Clear();
// 清除后强制刷新布局
RefreshLayout();
}
/// <summary>
/// 同步单位技能数据到状态显示区域
/// 仅显示 SkillInfo.ShowOnUnitMono = true 且当前单位拥有的技能
/// </summary>
public void SyncWithUnitSkills(UnitData unitData)
{
if (unitData == null || unitData.Skills == null) return;
var showSkills = new HashSet<SkillType>();
foreach (var skill in unitData.Skills)
{
if (skill == null) continue;
var skillType = skill.GetSkillType();
if (!Table.Instance.SkillDataAssets.GetSkillInfo(skillType, out var skillInfo)) continue;
if (SkillDataAssets.ShouldShowOnUnitMono(skillType, skillInfo))
{
showSkills.Add(skillType);
}
}
if (HakureiNorwayHeroSkillUtil.HasAunnPetrifiedDefenseAuraState(Main.MapData, unitData)
&& Table.Instance.SkillDataAssets.GetSkillInfo(SkillType.AunnPetrifiedDefenseAura, out var aunnAuraInfo)
&& SkillDataAssets.ShouldShowOnUnitMono(SkillType.AunnPetrifiedDefenseAura, aunnAuraInfo))
showSkills.Add(SkillType.AunnPetrifiedDefenseAura);
showSkills.Remove(SkillType.AunnHeroDamageBearer);
var hasAunnHeroDamageBearerBuffState =
HakureiNorwayHeroSkillUtil.HasAunnHeroDamageBearerBuffState(Main.MapData, unitData);
if (HakureiNorwayHeroSkillUtil.IsAunnBody(unitData) || !hasAunnHeroDamageBearerBuffState)
showSkills.Remove(SkillType.AunnHeroDamageBearerBuff);
else if (Table.Instance.SkillDataAssets.GetSkillInfo(SkillType.AunnHeroDamageBearerBuff,
out var aunnDamageBearerInfo)
&& SkillDataAssets.ShouldShowOnUnitMono(SkillType.AunnHeroDamageBearerBuff, aunnDamageBearerInfo))
showSkills.Add(SkillType.AunnHeroDamageBearerBuff);
var toRemove = new List<SkillType>();
foreach (var skillType in _statusIcons.Keys)
{
if (!showSkills.Contains(skillType))
toRemove.Add(skillType);
}
bool hasChanged = false;
foreach (var skillType in toRemove)
{
RemoveStatus(skillType);
hasChanged = true;
}
foreach (var skillType in showSkills)
{
if (!unitData.GetSkill(skillType, out _) &&
(skillType == SkillType.AunnPetrifiedDefenseAura &&
HakureiNorwayHeroSkillUtil.HasAunnPetrifiedDefenseAuraState(Main.MapData, unitData) ||
skillType == SkillType.AunnHeroDamageBearerBuff &&
hasAunnHeroDamageBearerBuffState))
{
const bool auraHasLevel = false;
const int auraLevel = 1;
if (!HasStatus(skillType) || GetStatusLevel(skillType) != auraLevel)
{
AddOrUpdateStatus(skillType, unitData.UnitFullType, auraHasLevel, auraLevel);
hasChanged = true;
}
else if (_statusIcons.TryGetValue(skillType, out var existingAuraIcon))
{
existingAuraIcon.IconMono.SetContent(skillType, unitData.UnitFullType, auraHasLevel,
auraLevel);
}
continue;
}
if (!unitData.GetSkill(skillType, out var skill))
{
if (HasStatus(skillType))
{
RemoveStatus(skillType);
hasChanged = true;
}
continue;
}
if (skill.HasLevel && skill.NoShow)
{
if (HasStatus(skillType))
{
RemoveStatus(skillType);
hasChanged = true;
}
continue;
}
bool hasLevel = skill.HasLevel;
int level = hasLevel ? skill.Level : 1;
if (!HasStatus(skillType) || GetStatusLevel(skillType) != level)
{
AddOrUpdateStatus(skillType, unitData.UnitFullType, hasLevel, level);
hasChanged = true;
}
else if (_statusIcons.TryGetValue(skillType, out var existingIcon))
{
existingIcon.IconMono.SetContent(skillType, unitData.UnitFullType, hasLevel, level);
}
}
if (hasChanged)
{
RefreshLayout();
}
}
/// <summary>
/// 刷新所有状态的显示位置(用于自动布局更新)
/// </summary>
public void RefreshLayout()
{
if (_statusContainer == null) return;
// 强制刷新布局
if (_statusContainer is UnityEngine.RectTransform rectTransform)
{
UnityEngine.UI.LayoutRebuilder.ForceRebuildLayoutImmediate(rectTransform);
}
// 图标增减后同时重排 InfoGroup让背景板等父级 LayoutGroup 感知尺寸变化
if (_infoGroup != null)
{
UnityEngine.UI.LayoutRebuilder.ForceRebuildLayoutImmediate(_infoGroup);
}
}
/// <summary>
/// 设置整个状态区域是否可见
/// </summary>
public void SetAreaVisible(bool visible)
{
if (_statusContainer != null)
_statusContainer.gameObject.SetActive(visible);
}
}
}