Files
bottlefish 17994d4b56 feat(emotionwave): empty 待机态、预设切换过渡、noiseOnlyBlend、渲染优化
empty 改为极弱噪波待机态;增加预设切换 crossfade 与 flash 效果;
noiseOnlyBlend 支持纯噪波渲染;两段式归一化使 fillAmount=1 正确填满;switch_emotion_wave_config 支持 progress 参数。

Made-with: Cursor
2026-03-12 15:26:08 +08:00

246 lines
7.3 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System.Collections;
using UnityEngine;
using DG.Tweening;
using AibisDream.FixSystem;
namespace AibisDream.MiniGame.HuoShan.EmotionWave
{
/// <summary>
/// 情绪波形管理器 - 用于控制情绪波形的显示、隐藏和进度动画
///
/// 功能:
/// - FixSystemCenter 注册/注销
/// - DOTween 显示/隐藏动画
/// - 进度控制:立即设置 + 平滑动画
/// - 平滑追踪:smoothstep lerp 追踪目标进度
/// </summary>
public class EmotionWaveManager : MonoBehaviour
{
#region 序列化字段
[Header("References")]
[SerializeField] private EmotionWaveController controller;
[SerializeField] private Transform containerTransform;
[Header("Slider Sync")]
[Tooltip("可选:关联 SliderController 以自动同步进度")]
[SerializeField] private SliderController sliderController;
[Tooltip("是否启用滑片同步(勾选后滑片进度会自动驱动情绪波形进度)")]
[SerializeField] private bool enableSliderSync = true;
[Header("动画设置")]
[SerializeField] private Vector2 hiddenPosition = new Vector2(0f, -600f);
[SerializeField] private Vector2 shownPosition = new Vector2(0f, 0f);
[SerializeField] private float showDuration = 0.5f;
[SerializeField] private float hideDuration = 0.3f;
[SerializeField] private Ease showEase = Ease.OutCubic;
[SerializeField] private Ease hideEase = Ease.InCubic;
[Header("Progress Settings")]
[SerializeField] private float lerpSpeed = 4f;
[Header("Debug")]
[SerializeField] [ReadOnly] private float currentProgress;
[SerializeField] [ReadOnly] private float targetProgress;
[SerializeField] [ReadOnly] private bool isShown;
#endregion
#region 私有字段
private Tweener _progressTweener;
private string _currentPresetId = "normal";
private AudioSource _audioSource;
#endregion
#region 预设
public string CurrentPresetId => _currentPresetId;
/// <summary>
/// 切换波形预设(normal / predicted / modified_joke / empty
/// empty 为低存在感待机态,会保留极弱噪波
/// </summary>
public void SetPreset(string presetId)
{
if (string.IsNullOrEmpty(presetId)) return;
_currentPresetId = presetId;
if (controller != null)
controller.SetPreset(presetId);
}
#endregion
#region 属性
public bool IsShown => isShown;
public float CurrentProgress => currentProgress;
public float TargetProgress => targetProgress;
#endregion
#region 生命周期
private void Awake()
{
_audioSource = GetComponent<AudioSource>();
if (_audioSource == null)
{
_audioSource = gameObject.AddComponent<AudioSource>();
}
// 初始化位置为隐藏状态(不控制 scale,由场景/Prefab 决定)
if (containerTransform != null)
{
containerTransform.localPosition = hiddenPosition;
}
// 注册到 FixSystemCenter
FixSystemCenter.SystemDic.Register(this);
// 订阅 SliderController 的进度事件
if (sliderController != null && enableSliderSync)
{
sliderController.onSliderPositionChanged.AddListener(OnSliderPositionChanged);
}
}
private void OnDestroy()
{
// 清理 DOTween
_progressTweener?.Kill();
// 取消订阅
if (sliderController != null)
{
sliderController.onSliderPositionChanged.RemoveListener(OnSliderPositionChanged);
}
// 注销
FixSystemCenter.SystemDic.Unregister<EmotionWaveManager>();
}
private void Update()
{
if (controller == null) return;
// smoothstep lerp 追踪目标进度(和 Web 版 lerpSpeed = 4.0 一致)
float dt = Time.deltaTime;
currentProgress += (targetProgress - currentProgress) * Mathf.Min(1f, dt * lerpSpeed);
// 将当前进度传递给 Controller
controller.Progress = currentProgress;
}
#endregion
#region 显示/隐藏动画
/// <summary>
/// 显示情绪波形(DOTween 动画)
/// </summary>
public IEnumerator Show(float duration = -1f)
{
if (isShown) yield break;
float actualDuration = duration > 0 ? duration : showDuration;
isShown = true;
if (containerTransform != null)
{
yield return containerTransform.DOLocalMove(shownPosition, actualDuration)
.SetEase(showEase)
.WaitForCompletion();
}
}
/// <summary>
/// 隐藏情绪波形(DOTween 动画)
/// </summary>
public IEnumerator Hide(float duration = -1f)
{
if (!isShown) yield break;
float actualDuration = duration > 0 ? duration : hideDuration;
isShown = false;
// 停止所有进度动画
_progressTweener?.Kill();
if (containerTransform != null)
{
yield return containerTransform.DOLocalMove(hiddenPosition, actualDuration)
.SetEase(hideEase)
.WaitForCompletion();
}
}
#endregion
#region 进度控制
/// <summary>
/// 立即设置进度(不等待)
/// </summary>
public void SetProgress(float value)
{
_progressTweener?.Kill();
targetProgress = Mathf.Clamp01(value);
currentProgress = targetProgress;
}
/// <summary>
/// 动画到指定进度(DOTween 驱动 targetProgress
/// </summary>
public IEnumerator AnimateToProgress(float target, float duration)
{
_progressTweener?.Kill();
target = Mathf.Clamp01(target);
// 使用 DOTween.To 驱动 targetProgress
_progressTweener = DOTween.To(
() => targetProgress,
x => targetProgress = x,
target,
duration
).SetEase(Ease.InOutCubic);
yield return _progressTweener.WaitForCompletion();
}
#endregion
#region Slider 同步
/// <summary>
/// 响应 SliderController 的位置变化事件
/// </summary>
private void OnSliderPositionChanged(float normalizedPosition)
{
if (!enableSliderSync) return;
// 滑片进度直接驱动 targetProgress(平滑追踪会在 Update 中处理)
targetProgress = Mathf.Clamp01(normalizedPosition);
}
/// <summary>
/// 启用/禁用滑片同步
/// </summary>
public void SetSliderSyncEnabled(bool enabled)
{
enableSliderSync = enabled;
}
#endregion
#region 辅助方法
[System.Serializable]
private class ReadOnlyAttribute : PropertyAttribute { }
#endregion
}
}