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 }