using System.Collections.Generic;
|
using UnityEngine;
|
using UnityEngine.UI;
|
using System;
|
using DG.Tweening;
|
|
/// <summary>
|
/// 战斗角色信息栏
|
/// 职责:显示角色血条、怒气、Buff和飘字提示
|
/// </summary>
|
public class BattleHeroInfoBar : MonoBehaviour
|
{
|
#region 内部类
|
|
/// <summary>
|
/// 飘字信息配置
|
/// </summary>
|
public class TipsInfo
|
{
|
public string message;
|
public bool useArtText;
|
public bool followCharacter;
|
public float scaleRatio;
|
public bool showBackground = false;
|
public bool useBuffColor = false; // 是否使用 Buff 颜色(从 FloatingConfig 读取)
|
public bool isDebuff = false; // 是否是负向 Buff(决定用哪个颜色)
|
}
|
|
#endregion
|
|
#region Inspector字段
|
|
[Header("UI Components")]
|
public Slider sliderHp;
|
public Slider sliderXp;
|
public BasicHeroInfoContainer heroInfoContainer;
|
public BattleTips textTips;
|
|
[Header("Buff Components")]
|
[SerializeField]
|
public List<BattleBuffCell> buffCells = new List<BattleBuffCell>();
|
|
[Header("Floating Configs")]
|
[Tooltip("跟随角色的飘字配置")]
|
public FloatingConfig followFloatingConfig;
|
[Tooltip("不跟随角色的飘字配置(固定在战场节点)")]
|
public FloatingConfig noFollowFloatingConfig;
|
|
[Header("Settings")]
|
public float PopUpInterval = 0.2f;
|
|
#endregion
|
|
#region 私有字段
|
|
protected BattleObject battleObject;
|
protected float timer = 0f;
|
|
protected List<TipsInfo> messages = new List<TipsInfo>();
|
protected List<BattleTips> tipsList = new List<BattleTips>();
|
protected List<HB428_tagSCBuffRefresh> buffList = new List<HB428_tagSCBuffRefresh>();
|
|
protected Tween hpTween;
|
protected Tween xpTween;
|
|
#endregion
|
|
#region Unity生命周期
|
|
protected void OnDisable()
|
{
|
CleanupTips();
|
}
|
|
#endregion
|
|
#region 公共方法 - 初始化
|
|
public void SetBattleObject(BattleObject _battleObject)
|
{
|
battleObject = _battleObject;
|
heroInfoContainer.SetHeroInfo(battleObject.teamHero);
|
RefreshBuff(battleObject.buffMgr.GetBuffList());
|
UpdateHP(battleObject.teamHero.curHp, battleObject.teamHero.curHp, battleObject.teamHero.maxHp, false);
|
UpdateXP(battleObject.teamHero.rage, battleObject.teamHero.rage, 100, false);
|
}
|
|
public void SetActive(bool active)
|
{
|
gameObject.SetActive(active);
|
}
|
|
#endregion
|
|
#region 公共方法 - Buff管理
|
|
public void RefreshBuff(List<HB428_tagSCBuffRefresh> datas)
|
{
|
if (buffCells.IsNullOrEmpty())
|
return;
|
|
for (int i = 0; i < buffCells.Count; i++)
|
{
|
if (i < datas.Count)
|
{
|
buffCells[i].SetActive(true);
|
buffCells[i].Init(datas[i], OnBuffCellClicked);
|
}
|
else
|
{
|
buffCells[i].SetActive(false);
|
}
|
}
|
}
|
|
#endregion
|
|
#region 公共方法 - 飘字管理
|
|
/// <summary>
|
/// 添加飘字到队列
|
/// </summary>
|
public void ShowTips(string message, bool useArtText = false, bool followCharacter = true, float scaleRatio = 1f)
|
{
|
messages.Add(new TipsInfo
|
{
|
message = message,
|
useArtText = useArtText,
|
followCharacter = followCharacter,
|
scaleRatio = scaleRatio
|
});
|
}
|
|
/// <summary>
|
/// 添加自定义飘字配置到队列
|
/// </summary>
|
public void ShowTips(TipsInfo tipsInfo)
|
{
|
messages.Add(tipsInfo);
|
}
|
|
#endregion
|
|
#region 公共方法 - 数值更新
|
|
/// <summary>
|
/// 更新血量显示
|
/// </summary>
|
public void UpdateHP(long fromHp, long toHp, long maxHp, bool tween = true)
|
{
|
KillTween(ref hpTween);
|
|
float targetValue = (float)toHp / (float)maxHp;
|
|
if (tween)
|
{
|
hpTween = sliderHp.DOValue(targetValue, 0.3f);
|
battleObject.battleField.battleTweenMgr.OnPlayTween(hpTween);
|
}
|
else
|
{
|
sliderHp.value = targetValue;
|
}
|
}
|
|
/// <summary>
|
/// 更新怒气显示
|
/// </summary>
|
public void UpdateXP(long fromXp, long toXp, long maxXp, bool tween = true)
|
{
|
KillTween(ref xpTween);
|
|
float targetValue = (float)toXp / (float)maxXp;
|
|
if (tween)
|
{
|
xpTween = sliderXp.DOValue(targetValue, 0.2f);
|
battleObject.battleField.battleTweenMgr.OnPlayTween(xpTween);
|
}
|
else
|
{
|
sliderXp.value = targetValue;
|
}
|
}
|
|
#endregion
|
|
#region 公共方法 - 运行时更新
|
|
/// <summary>
|
/// 每帧更新
|
/// </summary>
|
public void Run()
|
{
|
// 更新所有飘字
|
UpdateActiveTips();
|
|
// 处理飘字队列
|
ProcessTipsQueue();
|
}
|
|
/// <summary>
|
/// 设置速度比例
|
/// </summary>
|
public void SetSpeedRatio(float ratio)
|
{
|
foreach (var tip in tipsList)
|
{
|
tip.SetRatio(ratio, 1f);
|
}
|
}
|
|
#endregion
|
|
#region 私有方法 - 飘字处理
|
|
/// <summary>
|
/// 立即弹出飘字
|
/// </summary>
|
private void PopUpTipsDirectly(TipsInfo tipsInfo)
|
{
|
// 创建飘字实例
|
BattleTips tips = CreateTipsInstance(tipsInfo);
|
|
// 配置飘字
|
ConfigureTips(tips, tipsInfo);
|
|
// 设置位置(如果不跟随)
|
if (!tipsInfo.followCharacter)
|
{
|
SetNonFollowPosition(tips);
|
}
|
|
// 设置参数并显示
|
tips.SetRatio(battleObject.battleField.speedRatio, tipsInfo.scaleRatio);
|
tips.SetText(tipsInfo.message, tipsInfo.useArtText, false); // 移除 textColor 参数
|
tips.ShowBackground(tipsInfo.showBackground);
|
|
// 注册完成回调
|
tips.OnFinish = () => RemoveTips(tips);
|
|
// 添加到列表
|
tipsList.Add(tips);
|
}
|
|
/// <summary>
|
/// 创建飘字实例
|
/// </summary>
|
private BattleTips CreateTipsInstance(TipsInfo tipsInfo)
|
{
|
Transform parent = tipsInfo.followCharacter
|
? transform
|
: battleObject.battleField.battleRootNode.transform;
|
|
GameObject go = GameObject.Instantiate(textTips.gameObject, parent);
|
return go.GetComponent<BattleTips>();
|
}
|
|
/// <summary>
|
/// 配置飘字
|
/// </summary>
|
private void ConfigureTips(BattleTips tips, TipsInfo tipsInfo)
|
{
|
FloatingConfig targetConfig = tipsInfo.followCharacter
|
? followFloatingConfig
|
: noFollowFloatingConfig;
|
|
if (targetConfig == null)
|
{
|
Debug.LogError($"[BattleHeroInfoBar] FloatingConfig 未配置! " +
|
$"followCharacter={tipsInfo.followCharacter}, GameObject: {gameObject.name}");
|
return;
|
}
|
|
tips.SetFloatingConfig(targetConfig);
|
|
// 设置是否使用 Buff 颜色
|
if (tipsInfo.useBuffColor)
|
{
|
tips.SetBuffColor(true, tipsInfo.isDebuff);
|
}
|
}
|
|
/// <summary>
|
/// 设置不跟随飘字的位置
|
/// </summary>
|
private void SetNonFollowPosition(BattleTips tips)
|
{
|
RectTransform contentRect = tips.GetComponent<RectTransform>();
|
RectTransform contentParentRect = contentRect.parent as RectTransform;
|
RectTransform infoBarRect = GetComponent<RectTransform>();
|
|
// 计算世界坐标
|
Vector3 worldTargetPos = infoBarRect.transform.TransformPoint(infoBarRect.rect.center);
|
|
// 转换到父节点坐标
|
Vector2 anchoredPos;
|
RectTransformUtility.ScreenPointToLocalPointInRectangle(
|
contentParentRect,
|
RectTransformUtility.WorldToScreenPoint(null, worldTargetPos),
|
null,
|
out anchoredPos
|
);
|
|
// 设置动态位置
|
tips.SetPosition(anchoredPos, anchoredPos + new Vector2(0, 150));
|
}
|
|
/// <summary>
|
/// 移除飘字
|
/// </summary>
|
private void RemoveTips(BattleTips tips)
|
{
|
tipsList.Remove(tips);
|
GameObject.DestroyImmediate(tips.gameObject);
|
}
|
|
/// <summary>
|
/// 更新所有激活的飘字
|
/// </summary>
|
private void UpdateActiveTips()
|
{
|
for (int i = tipsList.Count - 1; i >= 0; i--)
|
{
|
tipsList[i].Run();
|
}
|
}
|
|
/// <summary>
|
/// 处理飘字队列
|
/// </summary>
|
private void ProcessTipsQueue()
|
{
|
timer += GetDeltaTime();
|
|
if (messages.Count > 0 && timer >= PopUpInterval)
|
{
|
TipsInfo tipsInfo = messages[0];
|
messages.RemoveAt(0);
|
|
PopUpTipsDirectly(tipsInfo);
|
|
timer = 0f;
|
}
|
}
|
|
/// <summary>
|
/// 清理所有飘字
|
/// </summary>
|
private void CleanupTips()
|
{
|
messages.Clear();
|
|
foreach (var tip in tipsList)
|
{
|
tip.OnFinish = null;
|
GameObject.DestroyImmediate(tip.gameObject);
|
}
|
|
tipsList.Clear();
|
}
|
|
#endregion
|
|
#region 私有方法 - 辅助方法
|
|
/// <summary>
|
/// 停止并清理Tween
|
/// </summary>
|
private void KillTween(ref Tween tween)
|
{
|
if (tween != null && battleObject != null)
|
{
|
battleObject.battleField.battleTweenMgr.OnKillTween(tween);
|
tween = null;
|
}
|
}
|
|
/// <summary>
|
/// 获取时间增量
|
/// </summary>
|
private float GetDeltaTime()
|
{
|
return 1f / (float)BattleConst.skillMotionFps * battleObject.battleField.speedRatio;
|
}
|
|
/// <summary>
|
/// Buff图标点击回调
|
/// </summary>
|
private void OnBuffCellClicked()
|
{
|
// TODO: 显示buff描述/当前身上所有buff
|
}
|
|
#endregion
|
}
|