using UnityEngine; using System; /// /// 战斗飘字UI控制器 /// 职责:处理飘字的缩放、透明度、位置动画逻辑 /// [Serializable] public class BattleFloatingUIController { #region 私有字段 private FloatingConfig config; private RectTransform rectTransform; private GameObject gameObject; private Action applyColorCallback; // 运行时状态 private float timer = 0f; private float speedRatio = 1f; private float scaleRatio = 1f; private bool isCritical = false; private Action onFinishCallback; // 运行时位置覆盖(优先级高于配置) 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 #region 构造函数 public BattleFloatingUIController( RectTransform rect, GameObject go, Action applyColor, FloatingConfig cfg) { rectTransform = rect; gameObject = go; applyColorCallback = applyColor; config = cfg; } #endregion #region 配置管理 /// /// 设置或更新配置 /// public void SetConfig(FloatingConfig cfg) { config = cfg; } /// /// 设置运行时位置覆盖(会覆盖配置中的位置) /// public void SetRuntimePosition(Vector2 beginPos, Vector2 endPos) { runtimeBeginPos = beginPos; runtimeEndPos = endPos; } /// /// 清除运行时位置覆盖,恢复使用配置中的位置 /// public void ClearRuntimePosition() { runtimeBeginPos = null; runtimeEndPos = null; } /// /// 设置运行时颜色覆盖(会覆盖配置中的颜色) /// public void SetRuntimeColor(Color beginColor, Color endColor) { runtimeBeginColor = beginColor; runtimeEndColor = endColor; } /// /// 清除运行时颜色覆盖,恢复使用配置中的颜色 /// public void ClearRuntimeColor() { runtimeBeginColor = null; runtimeEndColor = null; } #endregion #region 播放控制 /// /// 设置速度和缩放比例 /// public void SetRatio(float speed, float scale) { speedRatio = speed; scaleRatio = scale; } /// /// 开始播放动画 /// public void Play(bool isCrit, Action onComplete = null) { if (!ValidateConfig()) return; isCritical = isCrit; onFinishCallback = onComplete; timer = 0f; // 初始化位置和缩放 Vector2 beginPos = GetBeginPosition(); Vector3 beginScale = GetBeginScale(); rectTransform.anchoredPosition = beginPos; rectTransform.localScale = beginScale * scaleRatio; gameObject.SetActive(true); } /// /// 每帧更新 /// public void Run() { if (!gameObject.activeSelf || !ValidateConfig()) return; // 检查是否完成 if (timer >= config.totalShowTime) { OnAnimationComplete(); return; } // 更新动画 UpdatePosition(); UpdateScaleAndColor(); // 增加计时器 timer += GetDeltaTime(); } /// /// 暂停(预留接口) /// public void Stop() { // 可以添加暂停逻辑 } /// /// 恢复(预留接口) /// public void Resume() { // 可以添加恢复逻辑 } #endregion #region 私有方法 /// /// 验证配置有效性 /// private bool ValidateConfig() { if (config == null) { Debug.LogError("[BattleFloatingUIController] FloatingConfig 配置为空"); return false; } return true; } /// /// 获取起始位置(运行时位置优先) /// private Vector2 GetBeginPosition() { return runtimeBeginPos ?? config.beginPos; } /// /// 获取结束位置(运行时位置优先) /// private Vector2 GetEndPosition() { return runtimeEndPos ?? config.endPos; } /// /// 获取起始缩放 /// private Vector3 GetBeginScale() { return isCritical ? config.critBeginScale : config.normalBeginScale; } /// /// 获取结束缩放 /// private Vector3 GetEndScale() { return isCritical ? config.critEndScale : config.normalEndScale; } /// /// 获取时间增量 /// private float GetDeltaTime() { return 1f / BattleConst.skillMotionFps * speedRatio; } /// /// 更新位置 /// private void UpdatePosition() { float timeProgress = timer / config.totalShowTime; // 使用曲线来调整插值进度 float curveProgress = config.positionCurve.Evaluate(timeProgress); Vector2 currentPos = Vector2.Lerp(GetBeginPosition(), GetEndPosition(), curveProgress); rectTransform.anchoredPosition = currentPos; } /// /// 获取起始颜色(运行时颜色优先) /// private Color GetBeginColor() { return runtimeBeginColor ?? config.beginColor; } /// /// 获取结束颜色(运行时颜色优先) /// private Color GetEndColor() { return runtimeEndColor ?? config.endColor; } /// /// 更新缩放和颜色 /// private void UpdateScaleAndColor() { // 阶段1: 缩放和透明度变化 if (timer < config.scaleChangeTime) { float timeProgress = timer / config.scaleChangeTime; // 根据是否暴击选择对应的缩放曲线 AnimationCurve scaleCurve = isCritical ? config.critScaleCurve : config.normalScaleCurve; float scaleProgress = scaleCurve.Evaluate(timeProgress); Vector3 currentScale = Vector3.Lerp(GetBeginScale(), GetEndScale(), scaleProgress); rectTransform.localScale = currentScale * scaleRatio; // 使用曲线来调整颜色插值进度 float colorProgress = config.colorCurve.Evaluate(timeProgress); Color currentColor = Color.Lerp(GetBeginColor(), GetEndColor(), colorProgress); applyColorCallback?.Invoke(currentColor); } // 阶段2: 保持最终缩放和透明度 else { rectTransform.localScale = GetEndScale() * scaleRatio; applyColorCallback?.Invoke(GetEndColor()); } } /// /// 动画完成回调 /// private void OnAnimationComplete() { gameObject.SetActive(false); onFinishCallback?.Invoke(); onFinishCallback = null; } #endregion }