using System.Collections;
using UnityEngine;
using UnityEngine.UI;
using DG.Tweening;
using AibisDream.FixSystem;
namespace AibisDream.MiniGame.HuoShan
{
///
/// 波形检测器 - 用于显示和分析波形
///
/// 功能:
/// - 显示各种波形(情绪、逻辑、笑话等)
/// - 扫描模式:拖动进度条寻找清晰波形
/// - 波形效果:检测闪烁、变换动画等
///
public class WaveformDetector : MonoBehaviour
{
#region 序列化字段
[Header("设备配置")]
[SerializeField] private WaveformConfig waveformConfig;
[SerializeField] private Transform deviceContainer;
[Header("波形渲染器")]
[SerializeField] private WaveformRenderer primaryWaveform;
[Header("动画设置")]
[SerializeField] private Vector2 hiddenPosition = new Vector2(800f, 0f);
[SerializeField] private Vector2 shownPosition = new Vector2(0f, 0f);
[SerializeField] private float slideInDuration = 0.5f;
[SerializeField] private float slideOutDuration = 0.3f;
// 复古机械感:避免OutBack/InBack这种“弹簧感”过强的曲线
[SerializeField] private Ease slideInEase = Ease.OutCubic;
[SerializeField] private Ease slideOutEase = Ease.InCubic;
[Header("扫描UI")]
[SerializeField] private GameObject scannerPanel;
[SerializeField] private Slider scanSlider;
[SerializeField] private RawImage visitedAreaImage;
[SerializeField] private Text scanStatusText;
[SerializeField] private Button lockButton;
[SerializeField] private Text lockButtonText;
[Header("扫描设置")]
[SerializeField] private float clearPointPosition = 0.35f;
[SerializeField] private float clearThreshold = 0.15f;
[SerializeField] private float visitedCoverageRequired = 0.9f;
[SerializeField] private float notFoundDelay = 1f;
[Header("扫描表现")]
[SerializeField] private float scanBlurClarity = 0.06f;
[SerializeField] private float scanBlurNoise = 0.75f;
[SerializeField] private float scanClearNoise = 0.08f;
[SerializeField] private float scanClarityWidth = 0.06f;
[SerializeField] private float scanClarityRangeMultiplier = 2.0f;
[SerializeField] private float scanClarityPower = 2.2f;
[SerializeField] private float scanLogicSwitchClarity = 0.7f;
[SerializeField] private Vector2 scanFilterLogicWeightRange = new Vector2(0.35f, 0.6f);
[SerializeField] private Vector2 scanFilterJokeWeightRange = new Vector2(0.7f, 0.3f);
[Header("结果UI")]
[SerializeField] private GameObject resultPanel;
[SerializeField] private Text resultText;
[Header("连接状态")]
[SerializeField] private Text connectionStatusText;
[SerializeField] private Image connectionIndicator;
[Header("复古机械风格(UI/提示色)")]
[SerializeField] private bool useMechanicalUiStyle = true;
[SerializeField] private Color uiOnlineColor = new Color(0.30f, 0.90f, 0.55f, 1f); // CRT绿
[SerializeField] private Color uiOfflineColor = new Color(0.40f, 0.40f, 0.40f, 1f);
[SerializeField] private Color uiWarnColor = new Color(1.00f, 0.70f, 0.20f, 1f); // 仪表琥珀
[SerializeField] private Color uiErrorColor = new Color(0.95f, 0.30f, 0.25f, 1f);
[SerializeField] private Color visitedColor = new Color(0.30f, 0.90f, 0.55f, 0.65f);
[SerializeField] private Color unvisitedColor = new Color(0.18f, 0.18f, 0.18f, 0.35f);
[SerializeField] private Color sweepScanLineColor = new Color(1.00f, 0.70f, 0.20f, 0.85f);
[Header("复古机械风格(文案)")]
[SerializeField] private string statusPrefix = "状态:";
[SerializeField] private string scanCalibratingText = "校准中:调节游标,寻找稳定窗口…";
[SerializeField] private string scanSearchingText = "扫描中:寻找稳定窗口…";
[SerializeField] private string scanFineTuneText = "信号趋稳:继续微调…";
[SerializeField] private string scanReadyToLockText = "信号稳定:允许锁定";
[SerializeField] private string scanCompletedNotFoundText = "扫描完成:未检出匹配波形";
[SerializeField] private string emotionNotFoundText = "扫描完成:输出端未检出原始情绪波形";
[Header("音效")]
[SerializeField] private AudioClip scanSound;
[SerializeField] private AudioClip lockSound;
[SerializeField] private AudioClip notFoundSound;
[SerializeField] private AudioClip connectSound;
[SerializeField] private AudioClip transformSound;
#endregion
#region 私有字段
private bool _isShown = false;
private AudioSource _audioSource;
// 扫描模式
private bool _isScanMode = false;
private ScanMode _currentScanMode = ScanMode.None;
private bool _isLocked = false;
private float _lockedPosition = 0f;
private string _lockedTimestamp = "";
// 已访问区域追踪
private bool[] _visitedSegments;
private int _segmentCount = 100;
private float _visitedCoverage = 0f;
private bool _fullyCovered = false;
private float _notFoundTimer = 0f;
private bool _notFoundTriggered = false;
private Texture2D _visitedTexture;
// 当前连接的模块
private string _connectedModuleId = "";
#endregion
#region 枚举
public enum ScanMode
{
None,
Logic,
Emotion
}
#endregion
#region 属性
public bool IsShown => _isShown;
public bool IsScanMode => _isScanMode;
public bool IsLocked => _isLocked;
public bool FullyCovered => _fullyCovered;
public bool NotFoundTriggered => _notFoundTriggered;
public string LockedTimestamp => _lockedTimestamp;
public string ConnectedModuleId => _connectedModuleId;
#endregion
#region 生命周期
private void Awake()
{
_audioSource = GetComponent();
if (_audioSource == null)
{
_audioSource = gameObject.AddComponent();
}
if (deviceContainer != null)
{
deviceContainer.localPosition = hiddenPosition;
}
HideAllPanels();
_visitedSegments = new bool[_segmentCount];
CreateVisitedTexture();
if (scanSlider != null)
{
scanSlider.onValueChanged.AddListener(OnScanSliderChanged);
}
if (lockButton != null)
{
lockButton.onClick.AddListener(OnLockButtonClicked);
}
FixSystemCenter.SystemDic.Register(this);
}
private void OnDestroy()
{
if (scanSlider != null)
{
scanSlider.onValueChanged.RemoveListener(OnScanSliderChanged);
}
if (lockButton != null)
{
lockButton.onClick.RemoveListener(OnLockButtonClicked);
}
if (_visitedTexture != null)
{
Destroy(_visitedTexture);
}
FixSystemCenter.SystemDic.Unregister();
}
private void Update()
{
if (_isScanMode && _currentScanMode == ScanMode.Emotion && _fullyCovered && !_notFoundTriggered)
{
_notFoundTimer += Time.deltaTime;
if (_notFoundTimer >= notFoundDelay)
{
TriggerNotFound();
}
}
}
private void HideAllPanels()
{
if (scannerPanel != null) scannerPanel.SetActive(false);
if (resultPanel != null) resultPanel.SetActive(false);
}
#endregion
#region 设备显示/隐藏
public IEnumerator Show(float duration = -1f)
{
if (_isShown) yield break;
float actualDuration = duration > 0 ? duration : slideInDuration;
_isShown = true;
if (deviceContainer != null)
{
// 这里使用localPosition初始化,因此也使用DOLocalMove,避免世界坐标导致的“漂移感”
yield return deviceContainer.DOMove(shownPosition, actualDuration)
.SetEase(slideInEase)
.WaitForCompletion();
}
}
public IEnumerator Hide(float duration = -1f)
{
if (!_isShown) yield break;
float actualDuration = duration > 0 ? duration : slideOutDuration;
_isShown = false;
StopScanMode();
if (deviceContainer != null)
{
yield return deviceContainer.DOMove(hiddenPosition, actualDuration)
.SetEase(slideOutEase)
.WaitForCompletion();
}
if (primaryWaveform != null) primaryWaveform.SetVisible(false);
HideAllPanels();
}
#endregion
#region 模块连接
public IEnumerator ConnectToModule(string moduleId)
{
if (!_isShown)
{
yield return Show();
}
_connectedModuleId = moduleId;
PlaySound(connectSound);
if (connectionStatusText != null)
{
connectionStatusText.text = useMechanicalUiStyle
? $"LINK: ONLINE / {moduleId}"
: $"连接状态: 已联机 / {moduleId}";
}
if (connectionIndicator != null)
{
connectionIndicator.color = useMechanicalUiStyle ? uiOnlineColor : new Color(0.35f, 0.85f, 0.55f);
}
if (primaryWaveform != null)
{
var settings = waveformConfig.GetWaveformById("filter_output");
primaryWaveform.ApplySettings(settings);
primaryWaveform.SetNoiseAmount(0.8f);
primaryWaveform.SetClarity(0f);
primaryWaveform.SetVisible(true);
}
yield return new WaitForSeconds(0.3f);
}
public void Disconnect()
{
_connectedModuleId = "";
if (connectionStatusText != null)
{
connectionStatusText.text = useMechanicalUiStyle ? "LINK: OFFLINE" : "连接状态: 断开";
}
if (connectionIndicator != null)
{
connectionIndicator.color = useMechanicalUiStyle ? uiOfflineColor : new Color(0.45f, 0.45f, 0.45f);
}
StopScanMode();
}
#endregion
#region 波形显示
public IEnumerator ShowWaveform(string waveformId, float duration = 0.5f)
{
if (waveformConfig == null)
{
Debug.LogError("WaveformDetector: 波形配置未设置!");
yield break;
}
if (!_isShown)
{
yield return Show();
}
var settings = waveformConfig.GetWaveformById(waveformId);
if (primaryWaveform != null)
{
primaryWaveform.ApplySettings(settings);
primaryWaveform.SetClarity(1f);
primaryWaveform.SetNoiseAmount(0f);
primaryWaveform.SetVisible(true);
primaryWaveform.SetAlpha(0f);
float elapsed = 0f;
while (elapsed < duration)
{
elapsed += Time.deltaTime;
primaryWaveform.SetAlpha(elapsed / duration);
yield return null;
}
primaryWaveform.SetAlpha(1f);
}
}
public IEnumerator HideWaveform(float duration = 0.3f)
{
if (primaryWaveform != null && primaryWaveform.gameObject.activeInHierarchy)
{
float elapsed = 0f;
while (elapsed < duration)
{
elapsed += Time.deltaTime;
primaryWaveform.SetAlpha(1f - elapsed / duration);
yield return null;
}
primaryWaveform.SetVisible(false);
}
}
#endregion
#region 扫描模式
public IEnumerator EnableScanMode(ScanMode mode, string label = "扫描波形")
{
if (!_isShown)
{
yield return Show();
}
_isScanMode = true;
_currentScanMode = mode;
_isLocked = false;
_notFoundTriggered = false;
_notFoundTimer = 0f;
ResetVisitedArea();
if (mode == ScanMode.Logic)
{
clearPointPosition = Random.Range(0.25f, 0.45f);
}
else
{
clearPointPosition = -1f;
}
if (primaryWaveform != null && string.IsNullOrEmpty(_connectedModuleId))
{
yield return ConnectToModule("滤波器");
}
if (scannerPanel != null)
{
scannerPanel.SetActive(true);
}
if (scanSlider != null)
{
scanSlider.value = 0.5f;
scanSlider.interactable = true;
}
if (lockButton != null)
{
lockButton.interactable = false;
if (lockButtonText != null)
{
lockButtonText.text = "锁定";
}
}
if (scanStatusText != null)
{
scanStatusText.text = useMechanicalUiStyle
? $"{scanCalibratingText}({label})"
: $"校准中:移动游标{label}...";
}
UpdateWaveformByPosition(0.5f);
}
private void OnScanSliderChanged(float value)
{
if (!_isScanMode || _isLocked) return;
MarkVisited(value);
UpdateVisitedAreaDisplay();
UpdateWaveformByPosition(value);
bool isClear = IsNearClearPoint(value);
if (lockButton != null)
{
lockButton.interactable = isClear && _currentScanMode == ScanMode.Logic;
}
UpdateScanStatus(value, isClear);
}
private void UpdateWaveformByPosition(float position)
{
if (primaryWaveform == null) return;
if (_currentScanMode == ScanMode.Logic)
{
float distanceFromClear = Mathf.Abs(position - clearPointPosition);
float maxDistance = clearThreshold * scanClarityRangeMultiplier;
float t = 1f - Mathf.Clamp01(distanceFromClear / maxDistance);
float shaped = Mathf.Pow(t, scanClarityPower);
float clarity = Mathf.Lerp(scanBlurClarity, 1f, shaped);
float noiseAmount = Mathf.Lerp(scanBlurNoise, scanClearNoise, shaped);
primaryWaveform.SetClarityPosition(position);
primaryWaveform.SetClarityWidth(scanClarityWidth);
primaryWaveform.SetClarity(clarity);
primaryWaveform.SetNoiseAmount(noiseAmount);
if (clarity >= scanLogicSwitchClarity)
{
primaryWaveform.SetWaveType(WaveformType.Logic);
}
else
{
primaryWaveform.SetWaveType(WaveformType.FilterOutput);
float logicWeight = Mathf.Lerp(scanFilterLogicWeightRange.x, scanFilterLogicWeightRange.y, shaped);
float jokeWeight = Mathf.Lerp(scanFilterJokeWeightRange.x, scanFilterJokeWeightRange.y, shaped);
primaryWaveform.SetSynthesisWeights(logicWeight, jokeWeight);
}
}
else
{
primaryWaveform.SetClarityPosition(position);
primaryWaveform.SetClarity(0f);
primaryWaveform.SetNoiseAmount(0.8f);
}
}
private bool IsNearClearPoint(float position)
{
if (_currentScanMode != ScanMode.Logic) return false;
return Mathf.Abs(position - clearPointPosition) < clearThreshold * 0.5f;
}
private void UpdateScanStatus(float position, bool isClear)
{
if (scanStatusText == null) return;
if (_currentScanMode == ScanMode.Logic)
{
if (isClear)
{
scanStatusText.text = useMechanicalUiStyle
? $"{statusPrefix}{scanReadyToLockText}"
: "✓ 信号稳定,可执行锁定";
}
else
{
float distanceFromClear = Mathf.Abs(position - clearPointPosition);
if (distanceFromClear < clearThreshold)
{
scanStatusText.text = useMechanicalUiStyle
? $"{statusPrefix}{scanFineTuneText}"
: "信号趋稳中...继续微调";
}
else
{
scanStatusText.text = useMechanicalUiStyle
? $"{statusPrefix}{scanSearchingText}"
: "扫描中:寻找稳定窗口...";
}
}
}
else
{
if (_fullyCovered)
{
scanStatusText.text = useMechanicalUiStyle
? $"{statusPrefix}{scanCompletedNotFoundText}"
: "⚠ 扫描完成:未命中匹配波形";
}
else
{
scanStatusText.text = useMechanicalUiStyle
? $"{statusPrefix}扫描进度:{_visitedCoverage * 100:F0}%"
: $"扫描进度:{_visitedCoverage * 100:F0}%";
}
}
}
private void OnLockButtonClicked()
{
if (!_isScanMode || _isLocked) return;
if (_currentScanMode != ScanMode.Logic) return;
float currentPosition = scanSlider != null ? scanSlider.value : 0.5f;
if (!IsNearClearPoint(currentPosition)) return;
_isLocked = true;
_lockedPosition = currentPosition;
_lockedTimestamp = GenerateTimestamp();
PlaySound(lockSound);
if (lockButton != null)
{
lockButton.interactable = false;
if (lockButtonText != null)
{
lockButtonText.text = "✓ 已锁定";
}
}
if (scanSlider != null)
{
scanSlider.interactable = false;
}
if (scanStatusText != null)
{
scanStatusText.text = useMechanicalUiStyle
? $"{statusPrefix}锁定完成 | 时间戳: {_lockedTimestamp}"
: $"✓ 锁定完成 | 时间戳: {_lockedTimestamp}";
}
if (primaryWaveform != null)
{
primaryWaveform.SetClarity(1f);
primaryWaveform.SetNoiseAmount(0f);
primaryWaveform.SetWaveType(WaveformType.Logic);
}
Debug.Log($"WaveformDetector: 锁定成功,时间戳: {_lockedTimestamp}");
}
private void TriggerNotFound()
{
_notFoundTriggered = true;
PlaySound(notFoundSound);
if (scanStatusText != null)
{
scanStatusText.text = useMechanicalUiStyle
? $"{statusPrefix}{emotionNotFoundText}"
: "⚠ 扫描完成:未检出原始情绪波形";
}
if (scanSlider != null)
{
scanSlider.interactable = false;
}
Debug.Log("WaveformDetector: 情绪波形未找到");
}
public void StopScanMode()
{
_isScanMode = false;
_currentScanMode = ScanMode.None;
_isLocked = false;
if (scannerPanel != null)
{
scannerPanel.SetActive(false);
}
}
#endregion
#region 已访问区域追踪
private void CreateVisitedTexture()
{
_visitedTexture = new Texture2D(_segmentCount, 1, TextureFormat.RGBA32, false);
_visitedTexture.filterMode = FilterMode.Point;
_visitedTexture.wrapMode = TextureWrapMode.Clamp;
if (visitedAreaImage != null)
{
visitedAreaImage.texture = _visitedTexture;
}
ResetVisitedArea();
}
private void ResetVisitedArea()
{
for (int i = 0; i < _segmentCount; i++)
{
_visitedSegments[i] = false;
}
_visitedCoverage = 0f;
_fullyCovered = false;
UpdateVisitedAreaDisplay();
}
private void MarkVisited(float position)
{
int segmentIndex = Mathf.Clamp((int)(position * _segmentCount), 0, _segmentCount - 1);
int range = 3;
for (int i = segmentIndex - range; i <= segmentIndex + range; i++)
{
if (i >= 0 && i < _segmentCount)
{
_visitedSegments[i] = true;
}
}
int visitedCount = 0;
for (int i = 0; i < _segmentCount; i++)
{
if (_visitedSegments[i]) visitedCount++;
}
_visitedCoverage = (float)visitedCount / _segmentCount;
_fullyCovered = _visitedCoverage >= visitedCoverageRequired;
}
private void UpdateVisitedAreaDisplay()
{
if (_visitedTexture == null || visitedAreaImage == null) return;
for (int i = 0; i < _segmentCount; i++)
{
// 使用序列化颜色,便于整体风格统一(CRT绿/暗底)
_visitedTexture.SetPixel(i, 0, _visitedSegments[i] ? visitedColor : unvisitedColor);
}
_visitedTexture.Apply();
}
#endregion
#region 时间戳功能
private string GenerateTimestamp()
{
return $"07:12:{Random.Range(2, 10):D2}";
}
public IEnumerator ShowTimestampWaveform()
{
if (string.IsNullOrEmpty(_lockedTimestamp))
{
Debug.LogWarning("WaveformDetector: 没有锁定的时间戳");
yield break;
}
StopScanMode();
if (primaryWaveform != null)
{
var settings = waveformConfig.GetWaveformById("emotion");
primaryWaveform.ApplySettings(settings);
primaryWaveform.SetClarity(1f);
primaryWaveform.SetNoiseAmount(0f);
primaryWaveform.SetVisible(true);
}
ShowResult(true, $"时间戳 [{_lockedTimestamp}] 的原始波形\n类型:情绪波形(悲伤/压抑)\n⚠ 注意:波形与当前输出不一致");
yield return new WaitForSeconds(0.5f);
}
#endregion
#region 结果显示
public void ShowResult(bool isSuccess, string message)
{
if (resultPanel != null) resultPanel.SetActive(true);
if (resultText != null)
{
resultText.text = message;
if (useMechanicalUiStyle)
{
resultText.color = isSuccess ? uiOnlineColor : uiErrorColor;
}
else
{
resultText.color = isSuccess ? new Color(0.65f, 0.95f, 0.75f) : new Color(0.95f, 0.45f, 0.45f);
}
}
}
public void HideResult()
{
if (resultPanel != null) resultPanel.SetActive(false);
}
#endregion
#region 波形变换
public IEnumerator TransformWaveform(string fromWaveformId, string toWaveformId, float duration = 1f)
{
if (waveformConfig == null || primaryWaveform == null) yield break;
var fromSettings = waveformConfig.GetWaveformById(fromWaveformId);
var toSettings = waveformConfig.GetWaveformById(toWaveformId);
if (!_isShown) yield return Show();
primaryWaveform.ApplySettings(fromSettings);
primaryWaveform.SetClarity(1f);
primaryWaveform.SetNoiseAmount(0f);
primaryWaveform.SetVisible(true);
PlaySound(transformSound);
primaryWaveform.StartTransform(fromSettings.waveType, toSettings.waveType);
float elapsed = 0f;
while (elapsed < duration)
{
elapsed += Time.deltaTime;
float progress = elapsed / duration;
primaryWaveform.UpdateTransformProgress(progress);
Color currentPrimary = Color.Lerp(fromSettings.primaryColor, toSettings.primaryColor, progress);
Color currentSecondary = Color.Lerp(fromSettings.secondaryColor, toSettings.secondaryColor, progress);
primaryWaveform.SetColors(currentPrimary, currentSecondary);
// 用透明度闪烁代替位置抖动
if (progress > 0.3f && progress < 0.7f)
{
float intensity = 1 - Mathf.Abs(progress - 0.5f) * 2f;
float flicker = 0.7f + Mathf.Sin(progress * Mathf.PI * 20f) * intensity * 0.3f;
primaryWaveform.SetAlpha(flicker);
}
else
{
primaryWaveform.SetAlpha(1f);
}
yield return null;
}
primaryWaveform.FinishTransform();
primaryWaveform.ApplySettings(toSettings);
primaryWaveform.SetAlpha(1f);
}
#endregion
#region 波形效果
private struct WaveformVisualState
{
public Color PrimaryColor;
public Color SecondaryColor;
public float Alpha;
public float Clarity;
public float ClarityPosition;
public float ClarityWidth;
public float NoiseAmount;
}
private WaveformVisualState CaptureWaveformState()
{
return new WaveformVisualState
{
PrimaryColor = primaryWaveform.PrimaryColor,
SecondaryColor = primaryWaveform.SecondaryColor,
Alpha = primaryWaveform.CurrentAlpha,
Clarity = primaryWaveform.Clarity,
ClarityPosition = primaryWaveform.ClarityPosition,
ClarityWidth = primaryWaveform.ClarityWidth,
NoiseAmount = primaryWaveform.NoiseAmount
};
}
private void RestoreWaveformState(WaveformVisualState state)
{
primaryWaveform.SetColors(state.PrimaryColor, state.SecondaryColor);
primaryWaveform.SetClarity(state.Clarity);
primaryWaveform.SetClarityPosition(state.ClarityPosition);
primaryWaveform.SetClarityWidth(state.ClarityWidth);
primaryWaveform.SetNoiseAmount(state.NoiseAmount);
primaryWaveform.SetAlpha(state.Alpha);
}
///
/// 波形检测效果(闪烁)
///
public IEnumerator WaveformCheckEffect(int blinkCount = 3, float blinkInterval = 0.15f)
{
if (primaryWaveform == null) yield break;
WaveformVisualState originalState = CaptureWaveformState();
primaryWaveform.SetClarity(Mathf.Max(originalState.Clarity, 0.4f));
primaryWaveform.SetClarityWidth(Mathf.Max(originalState.ClarityWidth, 0.06f));
primaryWaveform.SetNoiseAmount(Mathf.Max(originalState.NoiseAmount, 0.25f));
for (int i = 0; i < blinkCount; i++)
{
yield return SweepAnalysis(blinkInterval, 0.05f, 0.95f);
primaryWaveform.SetAlpha(0.6f);
yield return new WaitForSeconds(blinkInterval * 0.3f);
primaryWaveform.SetAlpha(originalState.Alpha);
}
RestoreWaveformState(originalState);
}
///
/// 屏蔽词检测效果(扫描线从左到右扫过)
///
public IEnumerator WaveformSweepCheck(int sweepCount = 2, float sweepDuration = 0.25f)
{
if (primaryWaveform == null) yield break;
// 使用扫描线进行检测,不改变波形颜色
primaryWaveform.SetScanLineColor(useMechanicalUiStyle ? sweepScanLineColor : new Color(0.2f, 0.75f, 0.85f, 0.85f));
for (int i = 0; i < sweepCount; i++)
{
yield return SweepWithScanLine(sweepDuration, 0.02f, 0.98f);
yield return new WaitForSeconds(0.05f);
}
primaryWaveform.HideScanLine();
}
///
/// 限幅检测效果(显示上下限线并闪烁)
///
public IEnumerator WaveformRangeCheck(int pulseCount = 2, float pulseInterval = 0.12f)
{
if (primaryWaveform == null) yield break;
// 显示上下限线
primaryWaveform.ShowLimitLines();
for (int i = 0; i < pulseCount; i++)
{
// 闪烁效果
yield return LimitLinesPulse(pulseInterval);
yield return new WaitForSeconds(pulseInterval * 0.3f);
}
primaryWaveform.HideLimitLines();
}
private IEnumerator SweepAnalysis(float duration, float start, float end)
{
float elapsed = 0f;
while (elapsed < duration)
{
elapsed += Time.deltaTime;
float t = Mathf.Clamp01(elapsed / duration);
primaryWaveform.SetClarityPosition(Mathf.Lerp(start, end, t));
yield return null;
}
}
///
/// 使用扫描线进行横向扫描
///
private IEnumerator SweepWithScanLine(float duration, float start, float end)
{
primaryWaveform.ShowScanLine(start);
float elapsed = 0f;
while (elapsed < duration)
{
elapsed += Time.deltaTime;
float t = Mathf.Clamp01(elapsed / duration);
float position = Mathf.Lerp(start, end, t);
primaryWaveform.SetScanLinePosition(position);
yield return null;
}
}
///
/// 限幅线闪烁效果
///
private IEnumerator LimitLinesPulse(float duration)
{
float halfDuration = duration * 0.5f;
float elapsed = 0f;
// 淡入
while (elapsed < halfDuration)
{
elapsed += Time.deltaTime;
float alpha = Mathf.Lerp(0.3f, 1f, elapsed / halfDuration);
primaryWaveform.SetLimitLinesAlpha(alpha);
yield return null;
}
// 淡出
elapsed = 0f;
while (elapsed < halfDuration)
{
elapsed += Time.deltaTime;
float alpha = Mathf.Lerp(1f, 0.3f, elapsed / halfDuration);
primaryWaveform.SetLimitLinesAlpha(alpha);
yield return null;
}
}
private IEnumerator ProbeAt(float position, float duration)
{
primaryWaveform.SetClarityPosition(position);
primaryWaveform.SetAlpha(0.6f);
yield return new WaitForSeconds(duration);
primaryWaveform.SetAlpha(1f);
yield return new WaitForSeconds(duration * 0.5f);
}
///
/// 波形检测通过效果(绿色闪烁)
///
public IEnumerator WaveformCheckPass(float duration = 0.4f)
{
yield return FlashWaveformColor(Color.green, duration);
}
///
/// 波形检测失败/警告效果(红色闪烁)
///
public IEnumerator WaveformCheckFail(float duration = 0.6f)
{
yield return FlashWaveformColor(new Color(1f, 0.2f, 0.2f), duration);
}
///
/// 波形颜色闪烁效果
///
public IEnumerator FlashWaveformColor(Color flashColor, float duration, int flashCount = 3)
{
if (primaryWaveform == null) yield break;
Color originalPrimary = GetCurrentWaveformPrimaryColor();
Color originalSecondary = GetCurrentWaveformSecondaryColor();
float flashTime = duration / (flashCount * 2);
for (int i = 0; i < flashCount; i++)
{
primaryWaveform.SetColors(flashColor, flashColor);
yield return new WaitForSeconds(flashTime);
primaryWaveform.SetColors(originalPrimary, originalSecondary);
yield return new WaitForSeconds(flashTime);
}
}
private Color GetCurrentWaveformPrimaryColor()
{
if (primaryWaveform == null || waveformConfig == null) return Color.white;
switch (primaryWaveform.WaveType)
{
case WaveformType.Logic: return waveformConfig.logicWaveform.primaryColor;
case WaveformType.Emotion: return waveformConfig.emotionWaveform.primaryColor;
case WaveformType.Joke: return waveformConfig.jokeWaveform.primaryColor;
case WaveformType.FilterOutput: return waveformConfig.filterOutputWaveform.primaryColor;
default: return Color.white;
}
}
private Color GetCurrentWaveformSecondaryColor()
{
if (primaryWaveform == null || waveformConfig == null) return Color.gray;
switch (primaryWaveform.WaveType)
{
case WaveformType.Logic: return waveformConfig.logicWaveform.secondaryColor;
case WaveformType.Emotion: return waveformConfig.emotionWaveform.secondaryColor;
case WaveformType.Joke: return waveformConfig.jokeWaveform.secondaryColor;
case WaveformType.FilterOutput: return waveformConfig.filterOutputWaveform.secondaryColor;
default: return Color.gray;
}
}
#endregion
#region 辅助方法
private void PlaySound(AudioClip clip)
{
if (_audioSource != null && clip != null)
{
_audioSource.PlayOneShot(clip);
}
}
#endregion
}
}