| Main/Component/UI/Effect/ScriptableObject.meta | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| Main/Component/UI/Effect/ScriptableObject/FloatingConfig.cs | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| Main/Component/UI/Effect/ScriptableObject/FloatingConfig.cs.meta | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| Main/System/Battle/BattleField/RecordActions/BuffMountAction.cs | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| Main/System/Battle/BattleHUDWin.cs | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| Main/System/Battle/UIComp/BattleFloatingUIController.cs | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| Main/System/Battle/UIComp/BattleHeroInfoBar.cs | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| Main/System/Battle/UIComp/BattleTips.cs | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| Main/System/Battle/UIComp/DamageContent.cs | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 |
Main/Component/UI/Effect/ScriptableObject.meta
New file @@ -0,0 +1,8 @@ fileFormatVersion: 2 guid: c6e2ae278e429844e9d5da2ebc5e5d6d folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: Main/Component/UI/Effect/ScriptableObject/FloatingConfig.cs
New file @@ -0,0 +1,51 @@ using UnityEngine; /// <summary> /// 战斗飘字配置 ScriptableObject /// 用于配置飘字的动画效果参数 /// </summary> [CreateAssetMenu(fileName = "FloatingConfig", menuName = "Battle/FloatingConfig", order = 1)] public class FloatingConfig : ScriptableObject { [Header("Position Settings")] [Tooltip("起始位置偏移")] public Vector2 beginPos = Vector2.zero; [Tooltip("结束位置偏移")] public Vector2 endPos = new Vector2(0, 150); [Tooltip("位置移动曲线 (X轴=时间进度0-1, Y轴=插值进度0-1)")] public AnimationCurve positionCurve = AnimationCurve.Linear(0, 0, 1, 1); [Header("Time Settings")] [Tooltip("缩放变化时间 (约16帧)")] public float scaleChangeTime = 1f / BattleConst.skillMotionFps * 16f + 0.1f; [Tooltip("总显示时间 (约48帧)")] public float totalShowTime = 1f / BattleConst.skillMotionFps * 48f + 0.1f; [Header("Normal Animation Settings")] [Tooltip("普通飘字初始缩放")] public Vector3 normalBeginScale = new Vector3(2f, 2f, 2f); [Tooltip("普通飘字结束缩放")] public Vector3 normalEndScale = new Vector3(1f, 1f, 1f); [Header("Critical Animation Settings")] [Tooltip("暴击飘字初始缩放")] public Vector3 critBeginScale = new Vector3(3f, 3f, 3f); [Tooltip("暴击飘字结束缩放")] public Vector3 critEndScale = new Vector3(1.5f, 1.5f, 1.5f); [Tooltip("缩放变化曲线 (X轴=时间进度0-1, Y轴=插值进度0-1)")] public AnimationCurve scaleCurve = AnimationCurve.Linear(0, 0, 1, 1); [Header("Color Settings")] [Tooltip("初始颜色和透明度")] public Color beginColor = new Color(1f, 1f, 1f, 0.5f); [Tooltip("结束颜色和透明度")] public Color endColor = new Color(1f, 1f, 1f, 1f); [Tooltip("颜色变化曲线 (X轴=时间进度0-1, Y轴=插值进度0-1)")] public AnimationCurve colorCurve = AnimationCurve.Linear(0, 0, 1, 1); [Header("Buff Color Settings")] [Tooltip("正向Buff颜色 (增益buff)")] public Color gainBuffColor = Color.green; [Tooltip("负向Buff颜色 (debuff)")] public Color debuffColor = Color.red; } Main/Component/UI/Effect/ScriptableObject/FloatingConfig.cs.meta
New file @@ -0,0 +1,11 @@ fileFormatVersion: 2 guid: 900f40b168d3e0b4f9bebd9917a43c7e MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: Main/System/Battle/BattleField/RecordActions/BuffMountAction.cs
@@ -40,9 +40,11 @@ tipsInfo.useArtText = false; tipsInfo.followCharacter = true; tipsInfo.scaleRatio = 1f; tipsInfo.textColor = skillConfig.IsDebuff() ? Color.red : skillConfig.IsGainBuff() ? Color.green : Color.white; tipsInfo.showBackground = true; // 使用 Buff 颜色 tipsInfo.useBuffColor = true; tipsInfo.isDebuff = skillConfig.IsDebuff(); obj.heroInfoBar.ShowTips(tipsInfo); } Main/System/Battle/BattleHUDWin.cs
@@ -120,9 +120,10 @@ null, out anchoredPos); // 设置初始位置和结束位置 content.beginPos = anchoredPos; content.endPos = anchoredPos + new Vector2(0, 150); // 设置动态位置(会覆盖配置中的位置) Vector2 beginPos = anchoredPos; Vector2 endPos = anchoredPos + new Vector2(0, 150); content.SetPosition(beginPos, endPos); // 设置速度比例 if (battleField != null) Main/System/Battle/UIComp/BattleFloatingUIController.cs
@@ -2,117 +2,297 @@ using System; /// <summary> /// 战斗飘字UI控制器:处理缩放、透明度、位置动画逻辑 /// 战斗飘字UI控制器 /// 职责:处理飘字的缩放、透明度、位置动画逻辑 /// </summary> [SerializeField] [Serializable] 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 * 16f + 0.1f; // 7~8帧 (8/30=0.2667秒) public float totalShowTime = 1f / BattleConst.skillMotionFps * 48f + 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); #region 私有字段 // Color Settings public Color beginColor = new Color(1f, 1f, 1f, 0.5f); public Color endColor = new Color(1f, 1f, 1f, 1f); private FloatingConfig config; private RectTransform rectTransform; private GameObject gameObject; private Action<Color> applyColorCallback; // 运行时状态 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; // 运行时位置覆盖(优先级高于配置) private Vector2? runtimeBeginPos = null; private Vector2? runtimeEndPos = null; // 运行时颜色覆盖(优先级高于配置) private Color? runtimeBeginColor = null; private Color? runtimeEndColor = null; #endregion // 添加只读属性以对外暴露 #region 公共属性 public float Timer => timer; public float SpeedRatio => speedRatio; public float ScaleRatio => scaleRatio; #endregion public BattleFloatingUIController(RectTransform rect, GameObject go, Action<Color> applyColor) #region 构造函数 public BattleFloatingUIController( RectTransform rect, GameObject go, Action<Color> applyColor, FloatingConfig cfg) { rectTransform = rect; gameObject = go; applyColorCallback = applyColor; config = cfg; } #endregion #region 配置管理 /// <summary> /// 设置或更新配置 /// </summary> public void SetConfig(FloatingConfig cfg) { config = cfg; } /// <summary> /// 设置运行时位置覆盖(会覆盖配置中的位置) /// </summary> public void SetRuntimePosition(Vector2 beginPos, Vector2 endPos) { runtimeBeginPos = beginPos; runtimeEndPos = endPos; } /// <summary> /// 清除运行时位置覆盖,恢复使用配置中的位置 /// </summary> public void ClearRuntimePosition() { runtimeBeginPos = null; runtimeEndPos = null; } /// <summary> /// 设置运行时颜色覆盖(会覆盖配置中的颜色) /// </summary> public void SetRuntimeColor(Color beginColor, Color endColor) { runtimeBeginColor = beginColor; runtimeEndColor = endColor; } /// <summary> /// 清除运行时颜色覆盖,恢复使用配置中的颜色 /// </summary> public void ClearRuntimeColor() { runtimeBeginColor = null; runtimeEndColor = null; } #endregion #region 播放控制 /// <summary> /// 设置速度和缩放比例 /// </summary> public void SetRatio(float speed, float scale) { speedRatio = speed; scaleRatio = scale; } /// <summary> /// 开始播放动画 /// </summary> public void Play(bool isCrit, Action onComplete = null) { if (!ValidateConfig()) return; isCritical = isCrit; onFinishCallback = onComplete; timer = 0f; Vector3 beginScale = isCritical ? critBeginScale : normalBeginScale; // 初始化位置和缩放 Vector2 beginPos = GetBeginPosition(); Vector3 beginScale = GetBeginScale(); rectTransform.anchoredPosition = beginPos; rectTransform.localScale = beginScale * scaleRatio; gameObject.SetActive(true); } /// <summary> /// 每帧更新 /// </summary> public void Run() { if (!gameObject.activeSelf) if (!gameObject.activeSelf || !ValidateConfig()) return; if (timer >= totalShowTime) // 检查是否完成 if (timer >= config.totalShowTime) { gameObject.SetActive(false); onFinishCallback?.Invoke(); onFinishCallback = null; OnAnimationComplete(); 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; // 更新动画 UpdatePosition(); UpdateScaleAndColor(); // 增加计时器 timer += GetDeltaTime(); } /// <summary> /// 暂停(预留接口) /// </summary> public void Stop() { // 可以添加暂停逻辑 } /// <summary> /// 恢复(预留接口) /// </summary> public void Resume() { // 可以添加恢复逻辑 } #endregion #region 私有方法 /// <summary> /// 验证配置有效性 /// </summary> private bool ValidateConfig() { if (config == null) { Debug.LogError("[BattleFloatingUIController] FloatingConfig 配置为空"); return false; } return true; } /// <summary> /// 获取起始位置(运行时位置优先) /// </summary> private Vector2 GetBeginPosition() { return runtimeBeginPos ?? config.beginPos; } /// <summary> /// 获取结束位置(运行时位置优先) /// </summary> private Vector2 GetEndPosition() { return runtimeEndPos ?? config.endPos; } /// <summary> /// 获取起始缩放 /// </summary> private Vector3 GetBeginScale() { return isCritical ? config.critBeginScale : config.normalBeginScale; } /// <summary> /// 获取结束缩放 /// </summary> private Vector3 GetEndScale() { return isCritical ? config.critEndScale : config.normalEndScale; } /// <summary> /// 获取时间增量 /// </summary> private float GetDeltaTime() { return 1f / BattleConst.skillMotionFps * speedRatio; } /// <summary> /// 更新位置 /// </summary> private void UpdatePosition() { float moveProgress = timer / config.totalShowTime; Vector2 currentPos = Vector2.Lerp(GetBeginPosition(), GetEndPosition(), moveProgress); rectTransform.anchoredPosition = currentPos; } /// <summary> /// 获取起始颜色(运行时颜色优先) /// </summary> private Color GetBeginColor() { return runtimeBeginColor ?? config.beginColor; } /// <summary> /// 获取结束颜色(运行时颜色优先) /// </summary> private Color GetEndColor() { return runtimeEndColor ?? config.endColor; } /// <summary> /// 更新缩放和颜色 /// </summary> private void UpdateScaleAndColor() { // 阶段1: 缩放和透明度变化 if (timer < config.scaleChangeTime) { float progress = timer / config.scaleChangeTime; // 缩放插值 Vector3 currentScale = Vector3.Lerp(GetBeginScale(), GetEndScale(), progress); rectTransform.localScale = currentScale * scaleRatio; // 颜色插值(使用运行时颜色或配置颜色) Color currentColor = Color.Lerp(GetBeginColor(), GetEndColor(), progress); applyColorCallback?.Invoke(currentColor); } // 阶段2: 保持最终缩放和透明度 else { rectTransform.localScale = GetEndScale() * scaleRatio; applyColorCallback?.Invoke(GetEndColor()); } } /// <summary> /// 动画完成回调 /// </summary> private void OnAnimationComplete() { gameObject.SetActive(false); onFinishCallback?.Invoke(); onFinishCallback = null; } #endregion } Main/System/Battle/UIComp/BattleHeroInfoBar.cs
@@ -4,49 +4,78 @@ 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 Color textColor = Color.white; public bool showBackground = false; public bool useBuffColor = false; // 是否使用 Buff 颜色(从 FloatingConfig 读取) public bool isDebuff = false; // 是否是负向 Buff(决定用哪个颜色) } #endregion protected BattleObject battleObject; #region Inspector字段 [Header("UI Components")] public Slider sliderHp; public Slider sliderXp; //怒气 protected float timer = 0f; public float PopUpInterval = 0.2f; [SerializeField] public List<BattleBuffCell> buffCells = new List<BattleBuffCell>(); protected List<TipsInfo> messages = new List<TipsInfo>(); public Slider sliderXp; public BasicHeroInfoContainer heroInfoContainer; public BattleTips textTips; [Header("Buff Components")] [SerializeField] public List<BattleBuffCell> buffCells = new List<BattleBuffCell>(); protected Tween hpTween; [Header("Floating Configs")] [Tooltip("跟随角色的飘字配置")] public FloatingConfig followFloatingConfig; [Tooltip("不跟随角色的飘字配置(固定在战场节点)")] public FloatingConfig noFollowFloatingConfig; [Header("Settings")] public float PopUpInterval = 0.2f; #endregion protected Tween xpTween; #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; @@ -55,23 +84,27 @@ 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); HB428_tagSCBuffRefresh buffData = datas[i]; buffCells[i].Init(buffData, () => { // 点击buff图标 显示buff描述/当前身上所有buff }); buffCells[i].Init(datas[i], OnBuffCellClicked); } else { @@ -79,19 +112,14 @@ } } } #endregion protected void OnDisable() { // TODO YYL 考虑池化 messages.Clear(); for (int i = 0; i < tipsList.Count; i++) { var tip = tipsList[i]; tip.OnFinish = null; GameObject.DestroyImmediate(tip.gameObject); } tipsList.Clear(); } #region 公共方法 - 飘字管理 /// <summary> /// 添加飘字到队列 /// </summary> public void ShowTips(string message, bool useArtText = false, bool followCharacter = true, float scaleRatio = 1f) { messages.Add(new TipsInfo @@ -103,134 +131,266 @@ }); } /// <summary> /// 添加自定义飘字配置到队列 /// </summary> public void ShowTips(TipsInfo tipsInfo) { messages.Add(tipsInfo); } #endregion public void SetActive(bool active) #region 公共方法 - 数值更新 /// <summary> /// 更新血量显示 /// </summary> public void UpdateHP(long fromHp, long toHp, long maxHp, bool tween = true) { gameObject.SetActive(active); } public void PopUpTipsDirectly(TipsInfo tipsInfo) { GameObject prefab = textTips.gameObject; GameObject go = GameObject.Instantiate(prefab, tipsInfo.followCharacter ? transform : battleObject.battleField.battleRootNode.transform); BattleTips tips = go.GetComponent<BattleTips>(); if (!tipsInfo.followCharacter) { 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.SetRatio(battleObject.battleField.speedRatio, 1f); tips.SetText(tipsInfo.message, tipsInfo.useArtText, false, tipsInfo.textColor); tips.ShowBackground(tipsInfo.showBackground); tips.OnFinish = () => { tipsList.Remove(tips); GameObject.DestroyImmediate(tips.gameObject); }; tipsList.Add(tips); } public void UpdateHP(long fromHp, long toHp, long maxHp, bool tween = true) { // 做hp增加或者减少的动画 // sliderHp.value = ((float)fromHp) / ((float)maxHp); if (hpTween != null) { battleObject.battleField.battleTweenMgr.OnKillTween(hpTween); } KillTween(ref hpTween); float targetValue = (float)toHp / (float)maxHp; if (tween) { hpTween = sliderHp.DOValue((float)toHp / (float)maxHp, 0.3f); hpTween = sliderHp.DOValue(targetValue, 0.3f); battleObject.battleField.battleTweenMgr.OnPlayTween(hpTween); } else { sliderHp.value = ((float)toHp) / ((float)maxHp); sliderHp.value = targetValue; } // BattleDebug.LogError("update hp from " + fromHp + " to " + toHp + " maxHp " + maxHp); } /// <summary> /// 更新怒气显示 /// </summary> public void UpdateXP(long fromXp, long toXp, long maxXp, bool tween = true) { // 做Xp增加或者减少的动画 // sliderXp.value = ((float)fromXp) / ((float)maxXp); if (xpTween != null) { battleObject.battleField.battleTweenMgr.OnKillTween(xpTween); } KillTween(ref xpTween); float targetValue = (float)toXp / (float)maxXp; if (tween) { xpTween = sliderXp.DOValue((float)toXp / (float)maxXp, 0.2f); xpTween = sliderXp.DOValue(targetValue, 0.2f); battleObject.battleField.battleTweenMgr.OnPlayTween(xpTween); } else { sliderXp.value = ((float)toXp) / ((float)maxXp); sliderXp.value = targetValue; } // BattleDebug.LogError("update xp from " + fromXp + " to " + toXp + " maxXp " + maxXp); } #endregion #region 公共方法 - 运行时更新 /// <summary> /// 每帧更新 /// </summary> public void Run() { // 倒序遍历 删除.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(); } timer += 1f / (float)BattleConst.skillMotionFps * battleObject.battleField.speedRatio; } /// <summary> /// 处理飘字队列 /// </summary> private void ProcessTipsQueue() { timer += GetDeltaTime(); if (messages.Count > 0 && timer >= PopUpInterval) { // 播放飘字 TipsInfo tipsInfo = messages[0]; messages.RemoveAt(0); PopUpTipsDirectly(tipsInfo); timer = 0f; } } public void SetSpeedRatio(float ratio) /// <summary> /// 清理所有飘字 /// </summary> private void CleanupTips() { for (int i = 0; i < tipsList.Count; i++) messages.Clear(); foreach (var tip in tipsList) { tipsList[i].SetRatio(ratio, 1f); 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 } Main/System/Battle/UIComp/BattleTips.cs
@@ -2,79 +2,135 @@ using System; using UnityEngine.UI; /// <summary> /// 战斗飘字UI组件 /// 职责:管理UI元素和与控制器的交互 /// </summary> public class BattleTips : MonoBehaviour, IBattleFloatingUI { public Vector2 beginPos = Vector2.zero; public Vector2 endPos = new Vector2(0, 150); #region Inspector字段 [Header("UI Components")] public RectTransform rectTransform; public Text tipText; public Text artText; public Image background; public Vector3 normalBeginScale = new Vector3(2f, 2f, 2f); public Vector3 normalEndScale = new Vector3(1f, 1f, 1f); [Header("Floating Config")] [Tooltip("飘字动画配置,请在Inspector中拖拽赋值")] public FloatingConfig floatingConfig; #endregion public Action OnFinish; // 保留 OnFinish #region 公共字段 public Action OnFinish; // Buff 颜色相关 private bool useBuffColor = false; private bool isDebuff = false; #endregion [SerializeField] #region 私有字段 // 移除 [SerializeField],controller 不应该被序列化 private BattleFloatingUIController controller; #endregion void Awake() { InitController(); } private void InitController() { if (controller != null) return; controller = new BattleFloatingUIController(rectTransform, gameObject, ApplyColor); controller.beginPos = beginPos; controller.endPos = endPos; controller.normalBeginScale = normalBeginScale; controller.normalEndScale = normalEndScale; } #region 公共方法 /// <summary> /// 设置速度和缩放比例 /// </summary> public void SetRatio(float speed, float scale) { InitController(); // 确保 controller 已初始化 controller.SetRatio(speed, scale); EnsureControllerInitialized(); controller?.SetRatio(speed, scale); } public void SetText(string text, bool useArtText = false, bool isCrit = false, Color textColor = default) /// <summary> /// 设置运行时位置(用于不跟随角色的飘字) /// </summary> public void SetPosition(Vector2 beginPos, Vector2 endPos) { if (textColor == default) EnsureControllerInitialized(); controller?.SetRuntimePosition(beginPos, endPos); } /// <summary> /// 运行时更新配置 /// </summary> public void SetFloatingConfig(FloatingConfig config) { floatingConfig = config; if (controller != null) { textColor = Color.white; } InitController(); if (useArtText) { artText.text = text; tipText.gameObject.SetActive(false); artText.gameObject.SetActive(true); controller.SetConfig(config); } else { tipText.text = text; artText.gameObject.SetActive(false); tipText.gameObject.SetActive(true); InitController(); } } 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); /// <summary> /// 设置是否使用 Buff 颜色 /// </summary> public void SetBuffColor(bool useBuff, bool isDebuffBuff) { useBuffColor = useBuff; isDebuff = isDebuffBuff; // 如果使用 buff 颜色,立即设置运行时颜色覆盖 if (useBuffColor && floatingConfig != null) { Color buffColor = isDebuff ? floatingConfig.debuffColor : floatingConfig.gainBuffColor; Color beginColor = new Color(buffColor.r, buffColor.g, buffColor.b, floatingConfig.beginColor.a); Color endColor = new Color(buffColor.r, buffColor.g, buffColor.b, floatingConfig.endColor.a); EnsureControllerInitialized(); controller?.SetRuntimeColor(beginColor, endColor); } } /// <summary> /// 设置文本内容和样式 /// </summary> public void SetText(string text, bool useArtText = false, bool isCrit = false) { EnsureControllerInitialized(); // 切换文本显示类型 SwitchTextDisplay(useArtText, text); // 开始播放 Play(isCrit); } /// <summary> /// 显示/隐藏背景 /// </summary> public void ShowBackground(bool show) { if (background != null) background.enabled = show; } #endregion #region IBattleFloatingUI接口实现 public void Play(bool isCrit, Action onComplete = null) { InitController(); // 确保 controller 已初始化 EnsureControllerInitialized(); // 合并 OnFinish 和 onComplete if (controller == null) return; // 合并回调 Action combinedCallback = () => { OnFinish?.Invoke(); @@ -87,51 +143,100 @@ public void Run() { if (controller == null) return; // 防止在 Awake 前调用 controller.Run(); controller?.Run(); } public void Stop() { if (controller == null) return; controller.Stop(); controller?.Stop(); } public void Resume() { if (controller == null) return; controller.Resume(); controller?.Resume(); } #endregion #region 私有方法 /// <summary> /// 初始化控制器 /// </summary> private void InitController() { if (controller != null) return; if (floatingConfig == null) { Debug.LogError($"[BattleTips] FloatingConfig 未配置! GameObject: {gameObject.name}"); return; } controller = new BattleFloatingUIController( rectTransform, gameObject, ApplyColor, floatingConfig ); } /// <summary> /// 确保控制器已初始化 /// </summary> private void EnsureControllerInitialized() { if (controller == null) InitController(); } /// <summary> /// 切换文本显示类型 /// </summary> private void SwitchTextDisplay(bool useArtText, string text) { if (useArtText) { artText.text = text; tipText.gameObject.SetActive(false); artText.gameObject.SetActive(true); } else { tipText.text = text; artText.gameObject.SetActive(false); tipText.gameObject.SetActive(true); } } /// <summary> /// 应用文本颜色(保留配置的透明度) /// </summary> private void ApplyTextColor(Color textColor) { if (floatingConfig != null) { Color colorWithAlpha = new Color( textColor.r, textColor.g, textColor.b, floatingConfig.beginColor.a ); ApplyColor(colorWithAlpha); } } /// <summary> /// 应用颜色到激活的文本组件 /// </summary> 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; } #endregion } Main/System/Battle/UIComp/DamageContent.cs
@@ -9,15 +9,13 @@ public GameObject line; public RectTransform parent; public Vector2 beginPos = Vector2.zero; public Vector2 endPos = new Vector2(0, 150); [Header("Floating Config")] [Tooltip("请在Inspector中拖拽FloatingConfig资源")] public FloatingConfig floatingConfig; protected List<DamageLine> damageLineList = new List<DamageLine>(); private BattleDmgInfo battleDmgInfo; private BattleFloatingUIController controller; // 飘血优化:初始放大200%,透明度50%,7~8帧内缩放回100%,透明度回到100%,再往上飘14~16帧【30帧/秒】,暴击初始放大300%,缩回150% // 战斗帧BattleConst.skillMotionFps 1秒=30帧 void Awake() { @@ -28,26 +26,29 @@ { if (controller != null) return; if (floatingConfig == null) { Debug.LogError($"[DamageContent] FloatingConfig 未配置,请在Inspector中拖拽赋值! GameObject: {gameObject.name}"); return; } 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; controller = new BattleFloatingUIController(rectTransform, gameObject, ApplyColor, floatingConfig); } public void SetRatio(float speed, float scale) { InitController(); controller.SetRatio(speed, scale); controller?.SetRatio(speed, scale); } /// <summary> /// 设置飘字的起点和终点位置(运行时动态设置) /// </summary> public void SetPosition(Vector2 beginPos, Vector2 endPos) { InitController(); controller?.SetRuntimePosition(beginPos, endPos); } public async void SetDamage(BattleDmgInfo _damageInfo, Action _onComplete) @@ -81,10 +82,7 @@ public void Play(bool isCrit, Action onComplete = null) { InitController(); // 每次Play前更新controller的位置设置 controller.beginPos = beginPos; controller.endPos = endPos; controller.Play(isCrit, onComplete); controller?.Play(isCrit, onComplete); } public void Run() @@ -115,4 +113,14 @@ } } } // 运行时更新配置 public void SetFloatingConfig(FloatingConfig config) { floatingConfig = config; if (controller != null) { controller.SetConfig(config); } } }