using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using System;
using DG.Tweening;
///
/// 战斗角色信息栏
/// 职责:显示角色血条、怒气、Buff和飘字提示
///
public class BattleHeroInfoBar : MonoBehaviour
{
#region 内部类
///
/// 飘字信息配置
///
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 buffCells = new List();
[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 messages = new List();
protected List tipsList = new List();
protected List buffList = new List();
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 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 公共方法 - 飘字管理
///
/// 添加飘字到队列
///
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
});
}
///
/// 添加自定义飘字配置到队列
///
public void ShowTips(TipsInfo tipsInfo)
{
messages.Add(tipsInfo);
}
#endregion
#region 公共方法 - 数值更新
///
/// 更新血量显示
///
public void UpdateHP(long fromHp, long toHp, long maxHp, bool tween = true)
{
KillTween(ref hpTween);
float fromValue = (float)fromHp / (float)maxHp;
float targetValue = (float)toHp / (float)maxHp;
if (tween)
{
// 关键修复:先设置起始值,再播放动画到目标值
sliderHp.value = fromValue; // ← 这行是关键!
hpTween = sliderHp.DOValue(targetValue, 0.3f).SetAutoKill(false);
battleObject.battleField.battleTweenMgr.OnPlayTween(hpTween);
}
else
{
sliderHp.value = targetValue;
}
}
///
/// !!!临时的用于天子更新血量显示,等接口完善后删除
///
public void UpdateHP(float value)
{
sliderHp.value = value;
//Debug.Log("TianziDamageBar UpdateHP value:" + value);
}
///
/// 更新怒气显示
///
public void UpdateXP(long fromXp, long toXp, long maxXp, bool tween = true)
{
KillTween(ref xpTween);
float fromValue = (float)fromXp / (float)maxXp;
float targetValue = (float)toXp / (float)maxXp;
if (tween)
{
// 同样的修复
sliderXp.value = fromValue;
xpTween = sliderXp.DOValue(targetValue, 0.2f).SetAutoKill(false);
battleObject.battleField.battleTweenMgr.OnPlayTween(xpTween);
}
else
{
sliderXp.value = targetValue;
}
}
#endregion
#region 公共方法 - 运行时更新
///
/// 每帧更新
///
public void Run()
{
// 更新所有飘字
UpdateActiveTips();
// 处理飘字队列
ProcessTipsQueue();
}
///
/// 设置速度比例
///
public void SetSpeedRatio(float ratio)
{
foreach (var tip in tipsList)
{
tip.SetRatio(ratio, 1f);
}
}
#endregion
#region 私有方法 - 飘字处理
///
/// 立即弹出飘字
///
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);
}
///
/// 创建飘字实例
///
private BattleTips CreateTipsInstance(TipsInfo tipsInfo)
{
Transform parent = tipsInfo.followCharacter
? transform
: battleObject.battleField.battleRootNode.transform;
GameObject go = GameObject.Instantiate(textTips.gameObject, parent);
return go.GetComponent();
}
///
/// 配置飘字
///
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);
}
}
///
/// 设置不跟随飘字的位置
///
private void SetNonFollowPosition(BattleTips tips)
{
RectTransform contentRect = tips.GetComponent();
RectTransform contentParentRect = contentRect.parent as RectTransform;
RectTransform infoBarRect = GetComponent();
// 计算世界坐标
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));
}
///
/// 移除飘字
///
private void RemoveTips(BattleTips tips)
{
tipsList.Remove(tips);
GameObject.DestroyImmediate(tips.gameObject);
}
///
/// 更新所有激活的飘字
///
private void UpdateActiveTips()
{
for (int i = tipsList.Count - 1; i >= 0; i--)
{
tipsList[i].Run();
}
}
///
/// 处理飘字队列
///
private void ProcessTipsQueue()
{
timer += GetDeltaTime();
if (messages.Count > 0 && timer >= PopUpInterval)
{
TipsInfo tipsInfo = messages[0];
messages.RemoveAt(0);
PopUpTipsDirectly(tipsInfo);
timer = 0f;
}
}
///
/// 清理所有飘字
///
private void CleanupTips()
{
messages.Clear();
foreach (var tip in tipsList)
{
tip.OnFinish = null;
GameObject.DestroyImmediate(tip.gameObject);
}
tipsList.Clear();
}
#endregion
#region 私有方法 - 辅助方法
///
/// 停止并清理Tween
///
private void KillTween(ref Tween tween)
{
if (tween != null && battleObject != null)
{
battleObject.battleField.battleTweenMgr.OnKillTween(tween);
tween = null;
}
}
///
/// 获取时间增量
///
private float GetDeltaTime()
{
return 1f / (float)BattleConst.skillMotionFps * battleObject.battleField.speedRatio;
}
///
/// Buff图标点击回调
///
private void OnBuffCellClicked()
{
// TODO: 显示buff描述/当前身上所有buff
}
#endregion
}