From dc7922d80c1d133b6261b8af1d521567d2c0a35d Mon Sep 17 00:00:00 2001
From: hch <305670599@qq.com>
Date: 星期四, 30 十月 2025 16:51:39 +0800
Subject: [PATCH] Merge branch 'master' of http://mobile.secondworld.net.cn:10010/r/Project_SG_scripts

---
 Main/System/Battle/UIComp/DamageContent.cs                          |  148 +++++++----
 Main/System/Battle/UIComp/IBattleFloatingUI.cs.meta                 |   11 
 Main/System/Battle/BattleObject/BattleObjectFactory.cs              |    2 
 Main/System/Battle/BattleHUDWin.cs                                  |   71 +++-
 Main/System/Battle/UIComp/DamageLine.cs                             |   22 +
 Main/System/Battle/Motion/MotionBase.cs                             |    2 
 Main/System/Battle/Buff/BattleObjectBuffMgr.cs                      |   71 +++--
 Main/Core/NetworkPackage/CustomServerPack/CustomHB426CombinePack.cs |    4 
 Main/System/Battle/BattleField/BattleField.cs                       |   47 +--
 Main/System/Battle/UIComp/IBattleFloatingUI.cs                      |   14 +
 Main/System/Battle/BattleField/RecordActions/BuffMountAction.cs     |   11 
 Main/System/Battle/UIComp/BattleFloatingUIController.cs.meta        |   11 
 Main/System/Battle/BattleObject/BattleObject.cs                     |    1 
 Main/System/Battle/Skill/SkillBase.cs                               |    2 
 Main/Config/PartialConfigs/SkillConfig.Partial.cs                   |   17 +
 Main/System/Battle/UIComp/BattleHeroInfoBar.cs                      |   62 +++-
 Main/System/Battle/UIComp/BattleFloatingUIController.cs             |  118 +++++++++
 Main/System/Battle/UIComp/BattleTips.cs                             |  152 +++++++----
 18 files changed, 552 insertions(+), 214 deletions(-)

diff --git a/Main/Config/PartialConfigs/SkillConfig.Partial.cs b/Main/Config/PartialConfigs/SkillConfig.Partial.cs
index fd807b9..42bcf79 100644
--- a/Main/Config/PartialConfigs/SkillConfig.Partial.cs
+++ b/Main/Config/PartialConfigs/SkillConfig.Partial.cs
@@ -12,6 +12,13 @@
 
 public partial class SkillConfig : ConfigBase<int, SkillConfig>
 {
+//澧炵泭锛� 3 5
+// 鍑忕泭锛� 4 6 14
+
+	public static readonly int[] GainSkillType = new int[] { 3, 5 }; // 1-鏅�氭敾鍑� 2-琚姩鎶�鑳� 3-涓撳睘鎶�鑳�
+
+	public static readonly int[] DebuffSkillType = new int[] { 4, 6, 14 };
+
 	public SkillType skillType;
 	public SkillCastMode castMode;
 
@@ -45,6 +52,16 @@
 		tempDic[SkillLV] = this;
 	}
 
+	public bool IsGainBuff()
+    {
+        return Array.Exists(GainSkillType, type => type == (int)skillType);
+    }
+
+	public bool IsDebuff()
+    {
+        return Array.Exists(DebuffSkillType, type => type == (int)skillType);
+    }
+
 	public MotionName GetMotionName()
 	{
 		return Enum.Parse<MotionName>(SkillMotionName);
diff --git a/Main/Core/NetworkPackage/CustomServerPack/CustomHB426CombinePack.cs b/Main/Core/NetworkPackage/CustomServerPack/CustomHB426CombinePack.cs
index 8262b27..f509709 100644
--- a/Main/Core/NetworkPackage/CustomServerPack/CustomHB426CombinePack.cs
+++ b/Main/Core/NetworkPackage/CustomServerPack/CustomHB426CombinePack.cs
@@ -236,6 +236,10 @@
         {
             battleField.PlayRecord(skillAction);
         }
+        else
+        {
+            battleField.DistributeNextPackage();
+        }
 
     }
 
diff --git a/Main/System/Battle/BattleField/BattleField.cs b/Main/System/Battle/BattleField/BattleField.cs
index f926e10..8285e8e 100644
--- a/Main/System/Battle/BattleField/BattleField.cs
+++ b/Main/System/Battle/BattleField/BattleField.cs
@@ -8,50 +8,35 @@
 public class BattleField
 {
     public Action<int, int> OnRoundChange;
+    public Action<bool> OnBattlePause;
+
+    public Action<float> OnSpeedRatioChange; // 娣诲姞鎴樻枟閫熷害鍙樺寲鐨勫洖璋�
+
+    public Action OnBattleRun; // 娣诲姞鎴樻枟杩愯鏃剁殑鍥炶皟
 
     public BattleObjMgr battleObjMgr;
-
     public BattleEffectMgr battleEffectMgr;
-
     public BattleTweenMgr battleTweenMgr;
-
     public RecordPlayer recordPlayer;
-
     public IOperationAgent operationAgent;
 
     public byte turnMax;
-
     public int round = 0;
-
-    public string guid = string.Empty;//绛変簬string.Empty鐨勬椂鍊欎唬琛ㄦ槸StoryBattleField 鏄富绾垮壇鏈�
-
+    public string guid = string.Empty;
     public int MapID = 0;
-
     public int FuncLineID = 0;
-
     public float speedRatio = 1.1f;
-
     public JsonData extendData;
 
-    public bool IsBattleFinish
-    {
-        get;
-        protected set;
-    }
-
+    public bool IsBattleFinish { get; protected set; }
     public bool rejectNewPackage = false;
 
     private bool m_IsPause = false;
-
     public bool IsPause
     {
-        get
-        {
-            return m_IsPause;
-        }
+        get { return m_IsPause; }
         set
         {
-
             if (value)
             {
                 m_IsPause = value;
@@ -71,18 +56,12 @@
     }
 
     public BattleRootNode battleRootNode;
-
     private BattleMode battleMode;
     public event Action<BattleMode> ChangeBattleModeEvent;
 
-    public Action<bool> OnBattlePause;
-
     protected List<TeamBase> redTeamList = null;
-
     protected List<TeamBase> blueTeamList = null;
-
     protected int redTeamIndex = 0;
-
     protected int blueTeamIndex = 0;
 
     public BattleField(string _guid)
@@ -161,11 +140,17 @@
 
     public void SetSpeedRatio(float ratio)
     {
+        bool isChange = speedRatio != ratio;
         speedRatio = ratio;
         battleObjMgr.SetSpeedRatio(ratio);
         recordPlayer.SetSpeedRatio(ratio);
         battleEffectMgr.SetSpeedRatio(ratio);
         battleTweenMgr.SetSpeedRatio(ratio);
+
+        if (isChange)
+        {
+            OnSpeedRatioChange?.Invoke(ratio);
+        }
     }
 
     protected virtual void SetBattleStartState()
@@ -210,6 +195,7 @@
         }
         if (recordPlayer == null || battleObjMgr == null)
             return;
+        
         recordPlayer.Run();
         battleObjMgr.Run();
         battleEffectMgr.Run();
@@ -221,6 +207,9 @@
         }
 
         operationAgent.Run();
+        
+        // 瑙﹀彂 UI 灞傜殑鏇存柊鍥炶皟
+        OnBattleRun?.Invoke();
     }
 
 
diff --git a/Main/System/Battle/BattleField/RecordActions/BuffMountAction.cs b/Main/System/Battle/BattleField/RecordActions/BuffMountAction.cs
index 3ce6331..15731ff 100644
--- a/Main/System/Battle/BattleField/RecordActions/BuffMountAction.cs
+++ b/Main/System/Battle/BattleField/RecordActions/BuffMountAction.cs
@@ -35,7 +35,16 @@
                 if (null != skillConfig && obj != null)
                 {
                     //  椋樺瓧
-                    obj.heroInfoBar.ShowTips(skillConfig.SkillName);
+                    BattleHeroInfoBar.TipsInfo tipsInfo = new BattleHeroInfoBar.TipsInfo();
+                    tipsInfo.message = skillConfig.SkillName;
+                    tipsInfo.useArtText = false;
+                    tipsInfo.followCharacter = true;
+                    tipsInfo.scaleRatio = 1f;
+                    tipsInfo.textColor = skillConfig.IsDebuff() ?
+                                            Color.red : skillConfig.IsGainBuff() ? Color.green : Color.white;
+                    tipsInfo.showBackground = true;
+
+                    obj.heroInfoBar.ShowTips(tipsInfo);
                 }
             }
 
diff --git a/Main/System/Battle/BattleHUDWin.cs b/Main/System/Battle/BattleHUDWin.cs
index ef233a2..7a893e6 100644
--- a/Main/System/Battle/BattleHUDWin.cs
+++ b/Main/System/Battle/BattleHUDWin.cs
@@ -7,36 +7,23 @@
 using System;
 using LitJson;
 
-
 //  杩欎釜鐣岄潰鏄� persistent鐨勭晫闈�
 public class BattleHUDWin : UIBase
 {
-    // 缁勪欢寮曠敤
-    // private List<HUDContent> damageList = new List<HUDContent>();
-
-    // private List<BuffContent> buffList = new List<BuffContent>();
-
     private GameObjectPoolManager.GameObjectPool damagePrefabPool;
-
     private GameObjectPoolManager.GameObjectPool buffIconPrefabPool;
-
     private GameObjectPoolManager.GameObjectPool buffLabelPrefabPool;
 
     public Transform damageNode;
-
     public Transform buffIconNode;
-
     public Transform buffLabelNode;
 
     private BattleField battleField;
-
     private List<DamageContent> damageContentList = new List<DamageContent>();
 
-    // 鐢熷懡鍛ㄦ湡
     protected override void InitComponent()
     {
         base.InitComponent();
-        // 鍒濆鍖栫粍浠跺紩鐢� 缁戝畾鎸夐挳绛塙I缁勪欢浜嬩欢
     }
 
     protected override void OnPreOpen()
@@ -45,8 +32,6 @@
         EventBroadcast.Instance.AddListener<BattleDmgInfo>(EventName.BATTLE_DAMAGE_TAKEN, OnDamageTaken);
         EventBroadcast.Instance.AddListener<string, JsonData>(EventName.BATTLE_END, OnBattleEnd);
         damagePrefabPool = GameObjectPoolManager.Instance.RequestPool(UILoader.LoadPrefab("DamageContent"));
-        // buffIconPrefabPool = GameObjectPoolManager.Instance.RequestPool();
-        // buffLabelPrefabPool = GameObjectPoolManager.Instance.RequestPool(ResManager.Instance.LoadAsset<GameObject>("UIComp", "BuffContent"));
     }
 
     private void OnBattleEnd(string guid, JsonData data)
@@ -83,8 +68,13 @@
     protected override void OnClose()
     {
         base.OnClose();
-        battleField.OnBattlePause -= OnBattlePause;
-        battleField = null;
+        if (battleField != null)
+        {
+            battleField.OnBattlePause -= OnBattlePause;
+            battleField.OnBattleRun -= OnBattleRun;
+            battleField.OnSpeedRatioChange -= OnSpeedRatioChange;
+            battleField = null;
+        }
     }
 
     protected override void NextFrameAfterOpen()
@@ -108,13 +98,13 @@
         GameObject damageContent = damagePrefabPool.Request();
         DamageContent content = damageContent.GetComponent<DamageContent>();
         damageContent.transform.SetParent(damageNode, false);
-        damageContent.transform.localPosition = new Vector3(damageContent.transform.localPosition.x, damageContent.transform.localPosition.y, 0);
-        content.SetDamage(damageInfo, () => RemoveDamageContent(content));
-        damageContentList.Add(content);
-
+        
         var heroRect = damageInfo.hurtObj.heroRectTrans;
         if (heroRect == null)
+        {
+            damagePrefabPool.Release(damageContent);
             return;
+        }
 
         var contentRect = content.GetComponent<RectTransform>();
         var contentParentRect = contentRect.parent as RectTransform;
@@ -130,7 +120,19 @@
             null,
             out anchoredPos);
 
-        contentRect.anchoredPosition = anchoredPos;
+        // 璁剧疆鍒濆浣嶇疆鍜岀粨鏉熶綅缃�
+        content.beginPos = anchoredPos;
+        content.endPos = anchoredPos + new Vector2(0, 150);
+        
+        // 璁剧疆閫熷害姣斾緥
+        if (battleField != null)
+        {
+            content.SetRatio(battleField.speedRatio, 1f);
+        }
+
+        // 璁剧疆浼ゅ鏁版嵁骞跺紑濮嬫挱鏀�
+        content.SetDamage(damageInfo, () => RemoveDamageContent(content));
+        damageContentList.Add(content);
     }
 
     public void SetBattleField(BattleField _battleField)
@@ -138,15 +140,26 @@
         if (battleField != null)
         {
             battleField.OnBattlePause -= OnBattlePause;
+            battleField.OnBattleRun -= OnBattleRun;
+            battleField.OnSpeedRatioChange -= OnSpeedRatioChange;
         }
         ClearContent(string.Empty, true);
         battleField = _battleField;
         battleField.OnBattlePause += OnBattlePause;
+        battleField.OnBattleRun += OnBattleRun;
+        battleField.OnSpeedRatioChange += OnSpeedRatioChange;
+    }
+
+    private void OnSpeedRatioChange(float newSpeedRatio)
+    {
+        foreach (var content in damageContentList)
+        {
+            content.SetRatio(newSpeedRatio, 1f);
+        }
     }
 
     private void OnBattlePause(bool isPause)
     {
-        //  娓告垙鏆傚仠
         if (isPause)
         {
             foreach (var content in damageContentList)
@@ -154,7 +167,6 @@
                 content.Stop();
             }
         }
-        //  娓告垙鎭㈠
         else
         {
             foreach (var content in damageContentList)
@@ -163,4 +175,15 @@
             }
         }
     }
+
+    private void OnBattleRun()
+    {
+        for (int i = damageContentList.Count - 1; i >= 0; i--)
+        {
+            if (i < damageContentList.Count)
+            {
+                damageContentList[i].Run();
+            }
+        }
+    }
 }
diff --git a/Main/System/Battle/BattleObject/BattleObject.cs b/Main/System/Battle/BattleObject/BattleObject.cs
index 2ce9013..f868dee 100644
--- a/Main/System/Battle/BattleObject/BattleObject.cs
+++ b/Main/System/Battle/BattleObject/BattleObject.cs
@@ -504,6 +504,7 @@
     public void SetSpeedRatio(float ratio)
     {
         motionBase.SetSpeedRatio(ratio);
+        heroInfoBar.SetSpeedRatio(ratio);
     }
 
 
diff --git a/Main/System/Battle/BattleObject/BattleObjectFactory.cs b/Main/System/Battle/BattleObject/BattleObjectFactory.cs
index e9668f3..d40f987 100644
--- a/Main/System/Battle/BattleObject/BattleObjectFactory.cs
+++ b/Main/System/Battle/BattleObject/BattleObjectFactory.cs
@@ -11,7 +11,7 @@
 
     private static float m_modelScaleRate = 0f;
 
-    private static float modelScaleRate
+    public static float modelScaleRate
     {
         get
         {
diff --git a/Main/System/Battle/Buff/BattleObjectBuffMgr.cs b/Main/System/Battle/Buff/BattleObjectBuffMgr.cs
index da4099d..9e4f183 100644
--- a/Main/System/Battle/Buff/BattleObjectBuffMgr.cs
+++ b/Main/System/Battle/Buff/BattleObjectBuffMgr.cs
@@ -94,23 +94,24 @@
     //  鍒犻櫎buff
     public void RemoveBuff(HB429_tagSCBuffDel vNetData)
     {
-        HB428_tagSCBuffRefresh buffData = null;
-
-        bool isRemove = false;
-
-        if (buffDataDict.TryGetValue(vNetData.BuffID, out buffData))
-        {
-            isRemove = true;
-            buffDataDict.Remove(vNetData.BuffID);
-        }
-
-        if (!isRemove)
-        {
-            return;
-        }
-
+        var tempvNetData = vNetData;
         BuffUnmountAction buffRemoveAction = new BuffUnmountAction(battleObject.battleField, new List<HB429_tagSCBuffDel>() { vNetData }, () =>
         {
+            HB428_tagSCBuffRefresh buffData = null;
+
+            bool isRemove = false;
+
+            if (buffDataDict.TryGetValue(tempvNetData.BuffID, out buffData))
+            {
+                isRemove = true;
+                buffDataDict.Remove(tempvNetData.BuffID);
+            }
+
+            if (!isRemove)
+            {
+                return;
+            }
+
             bool isRemoveEffect = false;
 
             int remainCnt = -1;
@@ -143,7 +144,7 @@
 
                 if (buffGroupStateDict[BattleConst.HardControlGroup.ToString()].Contains(skillConfig.BuffState))
                 {
-                    BattleDebug.LogError("[BattleObjectBuffMgr]绉婚櫎瀵硅薄 " + battleObject.ObjID + " 鐨刡uff id " + vNetData.BuffID + " BuffState is " + skillConfig.BuffState + " 鏄惁鍒犻櫎浜嗗瓧鍏稿唴鐨勫唴瀹� " + isRemove.ToString() + " 鏄惁鍒犻櫎浜嗙壒鏁� " + isRemoveEffect.ToString() + " pack uid 鏄� " + vNetData.packUID);
+                    BattleDebug.LogError("[BattleObjectBuffMgr]绉婚櫎瀵硅薄 " + battleObject.ObjID + " 鐨刡uff id " + tempvNetData.BuffID + " BuffState is " + skillConfig.BuffState + " 鏄惁鍒犻櫎浜嗗瓧鍏稿唴鐨勫唴瀹� " + isRemove.ToString() + " 鏄惁鍒犻櫎浜嗙壒鏁� " + isRemoveEffect.ToString() + " pack uid 鏄� " + vNetData.packUID);
                 }
             }
 
@@ -173,21 +174,21 @@
             return;
         }
 
-        // bool isNew = false;
-        if (buffDataDict.ContainsKey(vNetData.BuffID))
-        {
-            buffDataDict[vNetData.BuffID] = vNetData;
-        }
-        else
-        {
-            // isNew = true;
-            buffDataDict.Add(vNetData.BuffID, vNetData);
-        }
+        var tempvNetData = vNetData;
 
-        if (vNetData.IsAdd != 0)
+        if (tempvNetData.IsAdd != 0)
         {
-            BuffMountAction buffMountAction = new BuffMountAction(battleObject.battleField, new List<HB428_tagSCBuffRefresh>() { vNetData }, () =>
+            BuffMountAction buffMountAction = new BuffMountAction(battleObject.battleField, new List<HB428_tagSCBuffRefresh>() { tempvNetData }, () =>
             {
+                if (buffDataDict.ContainsKey(tempvNetData.BuffID))
+                {
+                    buffDataDict[tempvNetData.BuffID] = tempvNetData;
+                }
+                else
+                {
+                    buffDataDict.Add(tempvNetData.BuffID, tempvNetData);
+                }
+
                 if (battleObject.IsDead())
                 {
                     return;
@@ -198,7 +199,7 @@
                     //  宸茬粡瀛樺湪鐩稿悓鐨刡uff鐗规晥
                     if (buffEffectDict.TryGetValue(skillConfig.BuffEffect, out KeyValuePair<BattleEffectPlayer, HashSet<uint>> pair))
                     {
-                        pair.Value.Add(vNetData.BuffID);
+                        pair.Value.Add(tempvNetData.BuffID);
                     }
                     else
                     {
@@ -209,7 +210,7 @@
                         effect.BindBone(battleObject.motionBase.skeletonAnim, effect.effectConfig.nodeName);
 
                         HashSet<uint> buffIdSet = new HashSet<uint>();
-                        buffIdSet.Add(vNetData.BuffID);
+                        buffIdSet.Add(tempvNetData.BuffID);
                         buffEffectDict.Add(skillConfig.BuffEffect, new KeyValuePair<BattleEffectPlayer, HashSet<uint>>(effect, buffIdSet));
                     }
 
@@ -217,7 +218,7 @@
 
                 if (skillConfig != null && buffGroupStateDict[BattleConst.HardControlGroup.ToString()].Contains(skillConfig.BuffState))
                 {
-                    BattleDebug.LogError("[BattleObjectBuffMgr]娣诲姞瀵硅薄 " + battleObject.ObjID + " 鐨刡uff id " + vNetData.BuffID + " pack uid 鏄� " + vNetData.packUID + " BuffState is " + skillConfig.BuffState);
+                    BattleDebug.LogError("[BattleObjectBuffMgr]娣诲姞瀵硅薄 " + battleObject.ObjID + " 鐨刡uff id " + tempvNetData.BuffID + " pack uid 鏄� " + tempvNetData.packUID + " BuffState is " + skillConfig.BuffState);
                 }
 
                 OnBuffChanged();
@@ -233,6 +234,14 @@
         }
         else
         {
+            if (buffDataDict.ContainsKey(tempvNetData.BuffID))
+            {
+                buffDataDict[tempvNetData.BuffID] = tempvNetData;
+            }
+            else
+            {
+                buffDataDict.Add(tempvNetData.BuffID, tempvNetData);
+            }
             //  宸茬粡瀛樺湪鐨刡uff 鍒锋柊
             OnBuffChanged();
         }
diff --git a/Main/System/Battle/Motion/MotionBase.cs b/Main/System/Battle/Motion/MotionBase.cs
index b086126..5a29950 100644
--- a/Main/System/Battle/Motion/MotionBase.cs
+++ b/Main/System/Battle/Motion/MotionBase.cs
@@ -5,7 +5,7 @@
 
 public class MotionBase
 {
-    public static float MotionTimeScale = 1f;
+    public float MotionTimeScale = 1f;
     public static List<string> AttackMotionList = new List<string>
     {
         MotionName.attack.ToString().ToLower(),
diff --git a/Main/System/Battle/Skill/SkillBase.cs b/Main/System/Battle/Skill/SkillBase.cs
index 43eb4e1..b8c46b5 100644
--- a/Main/System/Battle/Skill/SkillBase.cs
+++ b/Main/System/Battle/Skill/SkillBase.cs
@@ -150,7 +150,7 @@
             
             if (hintConfig != null)
             {
-                caster.heroInfoBar.ShowTips(((char)hintConfig.prefix).ToString(), true);
+                caster.heroInfoBar.ShowTips(((char)hintConfig.prefix).ToString(), true, false, 1.25f);
                 // Debug.Break();
             }
         }
diff --git a/Main/System/Battle/UIComp/BattleFloatingUIController.cs b/Main/System/Battle/UIComp/BattleFloatingUIController.cs
new file mode 100644
index 0000000..2b6b342
--- /dev/null
+++ b/Main/System/Battle/UIComp/BattleFloatingUIController.cs
@@ -0,0 +1,118 @@
+using UnityEngine;
+using System;
+
+/// <summary>
+/// 鎴樻枟椋樺瓧UI鎺у埗鍣�:澶勭悊缂╂斁銆侀�忔槑搴︺�佷綅缃姩鐢婚�昏緫
+/// </summary>
+[SerializeField]
+public class BattleFloatingUIController
+{
+    // Position Settings
+    public Vector2 beginPos = Vector2.zero;
+    public Vector2 endPos = new Vector2(0, 150);
+
+    // Time Settings
+    public float scaleChangeTime = 1f / BattleConst.skillMotionFps * 8f + 0.1f; // 7~8甯� (8/30=0.2667绉�)
+    public float totalShowTime = 1f / BattleConst.skillMotionFps * 24f + 0.1f; // 鎬绘椂闂寸害24甯� (8+16=24甯�)
+
+    // Normal Settings
+    public Vector3 normalBeginScale = new Vector3(2f, 2f, 2f);
+    public Vector3 normalEndScale = new Vector3(1f, 1f, 1f);
+
+    // Critical Settings
+    public Vector3 critBeginScale = new Vector3(3f, 3f, 3f);
+    public Vector3 critEndScale = new Vector3(1.5f, 1.5f, 1.5f);
+    
+    // Color Settings
+    public Color beginColor = new Color(1f, 1f, 1f, 0.5f);
+    public Color endColor = new Color(1f, 1f, 1f, 1f);
+
+    private RectTransform rectTransform;
+    private float timer = 0f;
+    private float speedRatio = 1f;
+    private float scaleRatio = 1f;
+    private bool isCritical = false;
+    private Action onFinishCallback;
+    private Action<Color> applyColorCallback;
+    private GameObject gameObject;
+
+    // 娣诲姞鍙灞炴�т互瀵瑰鏆撮湶
+    public float Timer => timer;
+    public float SpeedRatio => speedRatio;
+    public float ScaleRatio => scaleRatio;
+
+    public BattleFloatingUIController(RectTransform rect, GameObject go, Action<Color> applyColor)
+    {
+        rectTransform = rect;
+        gameObject = go;
+        applyColorCallback = applyColor;
+    }
+
+    public void SetRatio(float speed, float scale)
+    {
+        speedRatio = speed;
+        scaleRatio = scale;
+    }
+
+    public void Play(bool isCrit, Action onComplete = null)
+    {
+        isCritical = isCrit;
+        onFinishCallback = onComplete;
+        timer = 0f;
+        
+        Vector3 beginScale = isCritical ? critBeginScale : normalBeginScale;
+        rectTransform.anchoredPosition = beginPos;
+        rectTransform.localScale = beginScale * scaleRatio;
+        
+        gameObject.SetActive(true);
+    }
+
+    public void Run()
+    {
+        if (!gameObject.activeSelf)
+            return;
+
+        if (timer >= totalShowTime)
+        {
+            gameObject.SetActive(false);
+            onFinishCallback?.Invoke();
+            onFinishCallback = null;
+            return;
+        }
+
+        // 鏁翠釜杩囩▼閮藉線涓婇
+        float moveProgress = timer / totalShowTime;
+        rectTransform.anchoredPosition = Vector2.Lerp(beginPos, endPos, moveProgress);
+
+        Vector3 currentBeginScale = isCritical ? critBeginScale : normalBeginScale;
+        Vector3 currentEndScale = isCritical ? critEndScale : normalEndScale;
+
+        // 闃舵1: 7~8甯у唴缂╂斁鍜岄�忔槑搴﹀彉鍖�
+        if (timer < scaleChangeTime)
+        {
+            float scaleProgress = timer / scaleChangeTime;
+            rectTransform.localScale = Vector3.Lerp(currentBeginScale, currentEndScale, scaleProgress) * scaleRatio;
+
+            Color currentColor = Color.Lerp(beginColor, endColor, scaleProgress);
+            applyColorCallback?.Invoke(currentColor);
+        }
+        // 闃舵2: 淇濇寔缂╂斁鍜岄�忔槑搴︼紝缁х画寰�涓婇
+        else
+        {
+            rectTransform.localScale = currentEndScale * scaleRatio;
+            applyColorCallback?.Invoke(endColor);
+        }
+
+        timer += 1f / BattleConst.skillMotionFps * speedRatio;
+    }
+
+    public void Stop()
+    {
+        // 鍙互娣诲姞鏆傚仠閫昏緫
+    }
+
+    public void Resume()
+    {
+        // 鍙互娣诲姞鎭㈠閫昏緫
+    }
+}
\ No newline at end of file
diff --git a/Main/System/Battle/UIComp/BattleFloatingUIController.cs.meta b/Main/System/Battle/UIComp/BattleFloatingUIController.cs.meta
new file mode 100644
index 0000000..77d6b94
--- /dev/null
+++ b/Main/System/Battle/UIComp/BattleFloatingUIController.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 60d705fe96fb5584683592ecfef1ba81
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/System/Battle/UIComp/BattleHeroInfoBar.cs b/Main/System/Battle/UIComp/BattleHeroInfoBar.cs
index cfa66d5..1ba959c 100644
--- a/Main/System/Battle/UIComp/BattleHeroInfoBar.cs
+++ b/Main/System/Battle/UIComp/BattleHeroInfoBar.cs
@@ -12,6 +12,11 @@
         public string message;
         public bool useArtText;
         public bool followCharacter;
+        public float scaleRatio;
+
+        public Color textColor = Color.white;
+
+        public bool showBackground = false;
     }
 
     protected BattleObject battleObject;
@@ -87,14 +92,20 @@
         }
         tipsList.Clear();
     }
-    public void ShowTips(string message, bool useArtText = false, bool followCharacter = false)
+    public void ShowTips(string message, bool useArtText = false, bool followCharacter = true, float scaleRatio = 1f)
     {
         messages.Add(new TipsInfo
         {
             message = message,
             useArtText = useArtText,
-            followCharacter = followCharacter
+            followCharacter = followCharacter,
+            scaleRatio = scaleRatio
         });
+    }
+
+    public void ShowTips(TipsInfo tipsInfo)
+    {
+        messages.Add(tipsInfo);
     }
 
     public void SetActive(bool active)
@@ -102,28 +113,45 @@
         gameObject.SetActive(active);
     }
 
-    public void PopUpTipsDirectly(string message, bool useArtText = false, bool followCharacter = false)
+    public void PopUpTipsDirectly(TipsInfo tipsInfo)
     {
         GameObject prefab = textTips.gameObject;
 
-        GameObject go = GameObject.Instantiate(prefab, followCharacter ? transform : battleObject.battleField.battleRootNode.transform);
+        GameObject go = GameObject.Instantiate(prefab, tipsInfo.followCharacter ? transform : battleObject.battleField.battleRootNode.transform);
 
         BattleTips tips = go.GetComponent<BattleTips>();
 
-        if (!followCharacter)
+        if (!tipsInfo.followCharacter)
         {
-            go.transform.position = prefab.transform.position;
-            tips.beginPos = go.transform.localPosition;
-            tips.endPos = tips.endPos + new Vector2(go.transform.localPosition.x, go.transform.localPosition.y);
+            var contentRect = go.GetComponent<RectTransform>();
+            var contentParentRect = contentRect.parent as RectTransform;
+            var infoBarRect = GetComponent<RectTransform>();
+
+            Vector3 worldTargetPos = infoBarRect.transform.TransformPoint(infoBarRect.rect.center);
+
+            Vector2 anchoredPos;
+            RectTransformUtility.ScreenPointToLocalPointInRectangle(
+                contentParentRect,
+                RectTransformUtility.WorldToScreenPoint(null, worldTargetPos),
+                null,
+                out anchoredPos);
+
+            tips.UpdatePositions(anchoredPos, anchoredPos + new Vector2(0, 150));
+            
+            // 鍚屾椂鏇存柊缂╂斁
+            Vector3 newBeginScale = tips.normalBeginScale * tipsInfo.scaleRatio;
+            Vector3 newEndScale = tips.normalEndScale * tipsInfo.scaleRatio;
+            tips.UpdateScales(newBeginScale, newEndScale);
         }
 
-        tips.SetSpeedRatio(battleObject.battleField.speedRatio);
+        tips.SetRatio(battleObject.battleField.speedRatio, 1f);
 
-        tips.SetText(message, useArtText);
+        tips.SetText(tipsInfo.message, tipsInfo.useArtText, false, tipsInfo.textColor);
+
+        tips.ShowBackground(tipsInfo.showBackground);
 
         tips.OnFinish = () =>
         {
-            //  TODO YYL 鑰冭檻姹犲寲
             tipsList.Remove(tips);
             GameObject.DestroyImmediate(tips.gameObject);
         };
@@ -189,12 +217,20 @@
         if (messages.Count > 0 && timer >= PopUpInterval)
         {
             // 鎾斁椋樺瓧
-            TipsInfo message = messages[0];
+            TipsInfo tipsInfo = messages[0];
             messages.RemoveAt(0);
 
-            PopUpTipsDirectly(message.message, message.useArtText, message.followCharacter);
+            PopUpTipsDirectly(tipsInfo);
 
             timer = 0f;
         }
     }
+
+    public void SetSpeedRatio(float ratio)
+    {
+        for (int i = 0; i < tipsList.Count; i++)
+        {
+            tipsList[i].SetRatio(ratio, 1f);
+        }
+    }
 }
\ No newline at end of file
diff --git a/Main/System/Battle/UIComp/BattleTips.cs b/Main/System/Battle/UIComp/BattleTips.cs
index dfaff7c..bda5b8b 100644
--- a/Main/System/Battle/UIComp/BattleTips.cs
+++ b/Main/System/Battle/UIComp/BattleTips.cs
@@ -2,106 +2,136 @@
 using System;
 using UnityEngine.UI;
 
-public class BattleTips : MonoBehaviour
+public class BattleTips : MonoBehaviour, IBattleFloatingUI
 {
     public Vector2 beginPos = Vector2.zero;
     public Vector2 endPos = new Vector2(0, 150);
 
-    public float scaleChangeTime = 0.2667f; // 7~8甯� (8/30=0.2667绉�)
-    public float totalShowTime = 0.8f; // 鎬绘椂闂寸害24甯� (8+16=24甯�)
-    public float timer = 0f;
-
-    public Vector3 beginScale = new Vector3(4f, 4f, 4f);
-    public Vector3 endScale = new Vector3(2f, 2f, 2f);
-    public Color beginColor = new Color(1f, 1f, 1f, 0.5f);
-    public Color endColor = new Color(1f, 1f, 1f, 1f);
-
     public RectTransform rectTransform;
-
     public Text tipText;
-
     public Text artText;
 
-    public Action OnFinish;
+    public Image background;
 
-    private float speedRatio = 1f;
+    public Vector3 normalBeginScale = new Vector3(2f, 2f, 2f);
+    public Vector3 normalEndScale = new Vector3(1f, 1f, 1f);
 
-    public void SetSpeedRatio(float ratio)
+    public Action OnFinish; // 淇濈暀 OnFinish
+
+    [SerializeField]
+    private BattleFloatingUIController controller;
+
+    void Awake()
     {
-        speedRatio = ratio;
+        InitController();
     }
 
-    public void SetText(string text, bool useArtText = false)
+    private void InitController()
     {
-        //  鍒濆鏀惧ぇ200% 閫忔槑搴�50% 7~8甯у唴缂╁洖100% 閫忔槑搴﹀埌100% 鍐嶅線涓婇14~16甯� 鐒跺悗娑堝け 锛�30甯�/绉�)
+        if (controller != null) return;
 
-        // 8+16/30=0.8绉�
-        
+        controller = new BattleFloatingUIController(rectTransform, gameObject, ApplyColor);
+        controller.beginPos = beginPos;
+        controller.endPos = endPos;
+        controller.normalBeginScale =   normalBeginScale;
+        controller.normalEndScale = normalEndScale;
+    }
 
-        rectTransform.anchoredPosition = beginPos;
-        rectTransform.localScale = beginScale;
+    public void SetRatio(float speed, float scale)
+    {
+        InitController(); // 纭繚 controller 宸插垵濮嬪寲
+        controller.SetRatio(speed, scale);
+    }
 
-        timer = 0f;
-        gameObject.SetActive(true);
+    public void SetText(string text, bool useArtText = false, bool isCrit = false, Color textColor = default)
+    {
+        if (textColor == default)
+        {
+            textColor = Color.white;
+        }
 
+        InitController();
         if (useArtText)
         {
             artText.text = text;
-            artText.color = beginColor;
             tipText.gameObject.SetActive(false);
             artText.gameObject.SetActive(true);
         }
         else
         {
             tipText.text = text;
-            tipText.color = beginColor;
             artText.gameObject.SetActive(false);
             tipText.gameObject.SetActive(true);
         }
+
+        controller.beginColor = new Color(textColor.r, textColor.g, textColor.b, controller.beginColor.a);
+        controller.endColor = new Color(textColor.r, textColor.g, textColor.b, controller.endColor.a);
+        ApplyColor(controller.beginColor);
+        Play(isCrit);
     }
 
-
-    //  涓嶈浣跨敤update
-    public void Run()
+    public void Play(bool isCrit, Action onComplete = null)
     {
-        if (!gameObject.activeSelf)
-            return;
-
-        if (timer >= totalShowTime)
+        InitController(); // 纭繚 controller 宸插垵濮嬪寲
+        
+        // 鍚堝苟 OnFinish 鍜� onComplete
+        Action combinedCallback = () =>
         {
-            gameObject.SetActive(false);
             OnFinish?.Invoke();
             OnFinish = null;
-            return;
-        }
+            onComplete?.Invoke();
+        };
+        
+        controller.Play(isCrit, combinedCallback);
+    }
 
-        // 鏁翠釜杩囩▼閮藉線涓婇
-        float moveProgress = timer / totalShowTime;
-        rectTransform.anchoredPosition = Vector2.Lerp(beginPos, endPos, moveProgress);
+    public void Run()
+    {
+        if (controller == null) return; // 闃叉鍦� Awake 鍓嶈皟鐢�
+        controller.Run();
+    }
 
-        // 闃舵1: 7~8甯у唴缂╂斁浠巄eginScale鍒癳ndScale锛岄�忔槑搴︿粠50%鍒�100%
-        if (timer < scaleChangeTime)
-        {
-            float scaleProgress = timer / scaleChangeTime;
-            rectTransform.localScale = Vector3.Lerp(beginScale, endScale, scaleProgress);
+    public void Stop()
+    {
+        if (controller == null) return;
+        controller.Stop();
+    }
 
-            Color currentColor = Color.Lerp(beginColor, endColor, scaleProgress);
-            if (tipText.gameObject.activeSelf)
-                tipText.color = currentColor;
-            if (artText.gameObject.activeSelf)
-                artText.color = currentColor;
-        }
-        // 闃舵2: 缂╂斁瀹屾垚鍚庯紝淇濇寔endScale鍜�100%閫忔槑搴︼紝缁х画寰�涓婇
-        else
-        {
-            rectTransform.localScale = endScale;
-            
-            if (tipText.gameObject.activeSelf)
-                tipText.color = endColor;
-            if (artText.gameObject.activeSelf)
-                artText.color = endColor;
-        }
+    public void Resume()
+    {
+        if (controller == null) return;
+        controller.Resume();
+    }
 
-        timer += 1f / (float)BattleConst.skillMotionFps * speedRatio;
+    private void ApplyColor(Color color)
+    {
+        if (tipText.gameObject.activeSelf)
+            tipText.color = color;
+        if (artText.gameObject.activeSelf)
+            artText.color = color;
+    }
+
+    public void ShowBackground(bool showBackground)
+    {
+        // Implement the logic to show or hide the background
+        background.enabled = showBackground;
+    }
+
+    public void UpdatePositions(Vector2 begin, Vector2 end)
+    {
+        InitController();
+        beginPos = begin;
+        endPos = end;
+        controller.beginPos = begin;
+        controller.endPos = end;
+    }
+
+    public void UpdateScales(Vector3 beginScale, Vector3 endScale)
+    {
+        InitController();
+        normalBeginScale = beginScale;
+        normalEndScale = endScale;
+        controller.normalBeginScale = beginScale;
+        controller.normalEndScale = endScale;
     }
 }
\ No newline at end of file
diff --git a/Main/System/Battle/UIComp/DamageContent.cs b/Main/System/Battle/UIComp/DamageContent.cs
index 357149f..a87ed73 100644
--- a/Main/System/Battle/UIComp/DamageContent.cs
+++ b/Main/System/Battle/UIComp/DamageContent.cs
@@ -4,71 +4,115 @@
 using System;
 using Cysharp.Threading.Tasks;
 
-public class DamageContent : MonoBehaviour
+public class DamageContent : MonoBehaviour, IBattleFloatingUI
 {
-	public GameObject line;
+    public GameObject line;
+    public RectTransform parent;
 
-	public RectTransform parent;
+    public Vector2 beginPos = Vector2.zero;
+    public Vector2 endPos = new Vector2(0, 150);
 
-	protected List<DamageLine> damageLineList = new List<DamageLine>();
+    protected List<DamageLine> damageLineList = new List<DamageLine>();
+    private BattleDmgInfo battleDmgInfo;
+    private BattleFloatingUIController controller;
 
-	public PositionTween posTween;
+    //  椋樿浼樺寲锛氬垵濮嬫斁澶�200%锛岄�忔槑搴�50%锛�7~8甯у唴缂╂斁鍥�100%锛岄�忔槑搴﹀洖鍒�100%锛屽啀寰�涓婇14~16甯с��30甯�/绉掋�戯紝鏆村嚮鍒濆鏀惧ぇ300%锛岀缉鍥�150%
+    //	鎴樻枟甯attleConst.skillMotionFps 1绉�=30甯�
 
-	public ScaleTween scaleTween;
+    void Awake()
+    {
+        line.SetActive(false);
+    }
 
-	private BattleDmgInfo battleDmgInfo;
+    private void InitController()
+    {
+        if (controller != null) return;
 
-	void Awake()
-	{
-		line.SetActive(false);
-	}
+        RectTransform rectTransform = GetComponent<RectTransform>();
+        controller = new BattleFloatingUIController(rectTransform, gameObject, ApplyColor);
+        
+        // 浣跨敤褰撳墠璁剧疆鐨� beginPos 鍜� endPos
+        controller.beginPos = beginPos;
+        controller.endPos = endPos;
+        // controller.scaleChangeTime = scaleChangeTime;
+        // controller.totalShowTime = totalShowTime;
+        // controller.normalBeginScale = normalBeginScale;
+        // controller.normalEndScale = normalEndScale;
+        // controller.critBeginScale = critBeginScale;
+        // controller.critEndScale = critEndScale;
+        // controller.beginColor = beginColor;
+        // controller.endColor = endColor;
+    }
 
-	public async void SetDamage(BattleDmgInfo _damageInfo, Action _onComplete)
-	{
-		battleDmgInfo = _damageInfo;
+    public void SetRatio(float speed, float scale)
+    {
+        InitController();
+        controller.SetRatio(speed, scale);
+    }
 
-		var damages = battleDmgInfo.battleDamageList;
+    public async void SetDamage(BattleDmgInfo _damageInfo, Action _onComplete)
+    {
+        battleDmgInfo = _damageInfo;
 
-		for (int i = damages.Count; i < damageLineList.Count; i++)
-		{
-			damageLineList[i].SetActive(false);
-		}
+        var damages = battleDmgInfo.battleDamageList;
 
-		posTween.Play(_onComplete);
+        for (int i = damages.Count; i < damageLineList.Count; i++)
+        {
+            damageLineList[i].SetActive(false);
+        }
 
-		if (battleDmgInfo.IsCrit())
-		{
-			scaleTween.Play();
-		}
+        // 浣跨敤鎺у埗鍣ㄧ殑Play鏂规硶
+        bool isCrit = battleDmgInfo.IsCrit();
+        Play(isCrit, _onComplete);
 
-		for (int i = 0; i < damages.Count; i++)
-		{
-			if (i >= damageLineList.Count)
-			{
-				GameObject newLine = GameObject.Instantiate(line, parent);
-				damageLineList.Add(newLine.GetComponent<DamageLine>());
-			}
-			damageLineList[i].SetActive(true);
-			damageLineList[i].SetDamage(damages[i]);
-			await UniTask.Delay(100);
-		}
-	}
+        for (int i = 0; i < damages.Count; i++)
+        {
+            if (i >= damageLineList.Count)
+            {
+                GameObject newLine = GameObject.Instantiate(line, parent);
+                damageLineList.Add(newLine.GetComponent<DamageLine>());
+            }
+            damageLineList[i].SetActive(true);
+            damageLineList[i].SetDamage(damages[i]);
+            await UniTask.Delay(100);
+        }
+    }
 
-	public void Stop()
-	{
-		posTween.Stop();
-		if (battleDmgInfo.IsCrit())
-		{
-			scaleTween.Stop();
-		}
-	}
+    public void Play(bool isCrit, Action onComplete = null)
+    {
+        InitController();
+        // 姣忔Play鍓嶆洿鏂癱ontroller鐨勪綅缃缃�
+        controller.beginPos = beginPos;
+        controller.endPos = endPos;
+        controller.Play(isCrit, onComplete);
+    }
 
-	public void Resume()
-	{
-		posTween.Resume();
-		if (battleDmgInfo.IsCrit())
-		{
-			scaleTween.Resume();
-		}
-	}
+    public void Run()
+    {
+        if (controller == null) return;
+        controller.Run();
+    }
+
+    public void Stop()
+    {
+        if (controller == null) return;
+        controller.Stop();
+    }
+
+    public void Resume()
+    {
+        if (controller == null) return;
+        controller.Resume();
+    }
+
+    private void ApplyColor(Color color)
+    {
+        for (int i = 0; i < damageLineList.Count; i++)
+        {
+            if (damageLineList[i].gameObject.activeSelf)
+            {
+                damageLineList[i].SetColor(color);
+            }
+        }
+    }
 }
diff --git a/Main/System/Battle/UIComp/DamageLine.cs b/Main/System/Battle/UIComp/DamageLine.cs
index 3f37cd5..ccac5bc 100644
--- a/Main/System/Battle/UIComp/DamageLine.cs
+++ b/Main/System/Battle/UIComp/DamageLine.cs
@@ -1,6 +1,7 @@
 using System.Collections;
 using System.Collections.Generic;
 using UnityEngine;
+using UnityEngine.UI;
 
 public class DamageLine : MonoBehaviour
 {
@@ -26,4 +27,25 @@
         damageTypeLabel.SetActive(false);
         damageValueLabel.text = BattleUtility.DisplayDamageNum(damage);
     }
+
+    public void SetColor(Color color)
+    {
+        var text = GetComponent<Text>();
+        if (text != null)
+        {
+            text.color = color;
+        }
+
+        var texts = GetComponentsInChildren<Text>();
+        foreach (var t in texts)
+        {
+            t.color = color;
+        }
+
+        var images = GetComponentsInChildren<Image>();
+        foreach (var img in images)
+        {
+            img.color = color;
+        }
+    }
 }
diff --git a/Main/System/Battle/UIComp/IBattleFloatingUI.cs b/Main/System/Battle/UIComp/IBattleFloatingUI.cs
new file mode 100644
index 0000000..cde2509
--- /dev/null
+++ b/Main/System/Battle/UIComp/IBattleFloatingUI.cs
@@ -0,0 +1,14 @@
+using UnityEngine;
+using System;
+
+/// <summary>
+/// 鎴樻枟椋樺瓧UI鎺ュ彛
+/// </summary>
+public interface IBattleFloatingUI
+{
+    void Play(bool isCrit, Action onComplete = null);
+    void Run();
+    void Stop();
+    void Resume();
+    void SetRatio(float speed, float scale);
+}
\ No newline at end of file
diff --git a/Main/System/Battle/UIComp/IBattleFloatingUI.cs.meta b/Main/System/Battle/UIComp/IBattleFloatingUI.cs.meta
new file mode 100644
index 0000000..21596f1
--- /dev/null
+++ b/Main/System/Battle/UIComp/IBattleFloatingUI.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: a7d43ddbe5932644c82d307b759d51d8
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

--
Gitblit v1.8.0