Files
aibis-dream/Assets/Scripts/MiniGame/HuoShan/Waveform/WaveformRenderer.cs
T
2026-02-09 14:02:41 +08:00

1117 lines
44 KiB
C#

using UnityEngine;
namespace AibisDream.MiniGame.HuoShan
{
/// <summary>
/// 波形渲染器 - 单个波形的渲染
/// 支持噪波效果和清晰度控制,像录音软件中的声波
/// </summary>
[ExecuteInEditMode]
[RequireComponent(typeof(LineRenderer))]
public class WaveformRenderer : MonoBehaviour
{
public enum PreviewMode
{
Clean, // 清晰波形,无噪波
WithNoise, // 显示噪波效果
Runtime // 模拟运行时(噪波+清晰度)
}
public enum ConfigPreviewType
{
None, // 不使用Config,使用下方的手动设置
Emotion, // 预览情绪波形配置
Logic, // 预览逻辑波形配置
Joke, // 预览笑话波形配置
FilterOutput, // 预览滤波器输出配置
NormalOutput // 预览正常输出配置
}
[Header("═══ 从Config预览(拖入Config后选择类型即可预览)═══")]
[Tooltip("拖入WaveformConfig资源")]
[SerializeField] private WaveformConfig previewConfig;
[Tooltip("选择要预览的波形类型(选择后立即生效)")]
[SerializeField] private ConfigPreviewType previewFromConfig = ConfigPreviewType.None;
[Header("═══ 预览效果 ═══")]
[SerializeField] private PreviewMode editorPreviewMode = PreviewMode.Clean;
[Tooltip("勾选强制刷新波形显示")]
[SerializeField] private bool forceRefresh = false;
[Header("═══ 波形设置(手动调整或从Config应用)═══")]
[SerializeField] private WaveformType waveType = WaveformType.Emotion;
[SerializeField] private float waveHeight = 1f;
[SerializeField] private float waveWidth = 10f;
[SerializeField] private float waveSpeed = 2f;
[SerializeField] private float frequency = 1f;
[Header("噪波设置")]
[SerializeField] private float noiseAmount = 0.8f; // 噪波强度 (0=无噪波, 1=完全噪波)
[SerializeField] private float noiseFrequency = 15f; // 噪波频率
[SerializeField] private float noiseSpeed = 5f; // 噪波变化速度
[Header("清晰度设置")]
[SerializeField] private float clarity = 0f; // 清晰度 (0=模糊, 1=完全清晰)
[SerializeField] private float clarityPosition = 0.5f; // 清晰位置 (0-1)
[SerializeField] private float clarityWidth = 0.1f; // 清晰区域宽度
[Header("绘图设置")]
[SerializeField] private int resolution = 200;
[SerializeField] private float lineWidth = 0.05f;
[Header("颜色设置")]
[SerializeField] private Color primaryColor = Color.cyan;
[SerializeField] private Color secondaryColor = Color.blue;
[SerializeField] private Color noiseColor = new Color(0.5f, 0.5f, 0.5f, 0.5f);
[Tooltip("清晰区域使用主色调的高亮版本")]
[SerializeField] private bool useBrightenedClearColor = true;
[SerializeField] private float clearColorBrighten = 0.3f;
[Header("发光点")]
[SerializeField] private bool showGlowPoint = true;
[SerializeField] private SpriteRenderer glowPointRenderer;
[SerializeField] private float glowSize = 0.15f;
[Header("扫描线设置")]
[SerializeField] private Color scanLineColor = new Color(0.2f, 0.9f, 1f, 1f);
[SerializeField] private float scanLineWidthMultiplier = 0.8f; // 相对于波形线宽的倍数(更细)
[SerializeField] private Color limitLineColor = new Color(1f, 0.8f, 0.2f, 1f);
[SerializeField] private float limitLineWidthMultiplier = 0.6f; // 相对于波形线宽的倍数(更细)
[SerializeField] private string scanLineSortingLayer = "Tools";
[SerializeField] private int scanLineSortingOrderOffset = 1; // 在Tools层级上+1
[Header("复古示波器质感(可选)")]
[Tooltip("开启后会添加轻微的CRT抖动/亮度呼吸,让观感更像老式示波器/仪表屏")]
[SerializeField] private bool enableOscilloscopeArtifacts = true;
[Tooltip("亮度/透明度轻微闪烁强度(0-0.2建议)")]
[Range(0f, 0.2f)]
[SerializeField] private float crtFlickerAmount = 0.04f;
[Tooltip("垂直微抖动强度(以波形高度为基准的比例)")]
[Range(0f, 0.05f)]
[SerializeField] private float crtVerticalJitter = 0.008f;
[Tooltip("50/60Hz嗡鸣感(用于模拟电源纹波)")]
[Range(10f, 90f)]
[SerializeField] private float crtHumHz = 50f;
private LineRenderer _lineRenderer;
private LineRenderer _scanLineRenderer;
private LineRenderer _upperLimitLineRenderer;
private LineRenderer _lowerLimitLineRenderer;
private Vector3[] _points;
private float _phaseOffset = 0f;
private float _noisePhase = 0f;
private float _transformProgress = 0f;
private WaveformType _transformFromType;
private WaveformType _transformToType;
private bool _isTransforming = false;
private float _currentAlpha = 1f;
private float _crtAlphaMul = 1f;
// 变换效果参数
private float _transformDistortion = 0f; // 变换时的扭曲程度
private float _transformCompression = 1f; // 变换时的压缩程度
// 随机噪波种子
private float[] _noiseSeed;
// 合成模式参数
private float _logicWeight = 0.3f;
private float _jokeWeight = 0.85f;
private float _synthesisProgress = 1f;
// 情绪波形谐波参数(可通过配置调整)
private float _harmonicA1 = 0.55f; // 基波振幅
private float _harmonicA2 = 0.28f; // 二次谐波振幅
private float _harmonicA3 = 0.12f; // 三次谐波振幅
private float _harmonicPhase2 = 0.3f; // 二次谐波相位
private float _harmonicPhase3 = 0.5f; // 三次谐波相位
private float _verticalOffset = -0.08f; // 整体偏移
public WaveformType WaveType => waveType;
public bool IsTransforming => _isTransforming;
public float Clarity => clarity;
public float ClarityPosition => clarityPosition;
public float ClarityWidth => clarityWidth;
public float NoiseAmount => noiseAmount;
public Color PrimaryColor => primaryColor;
public Color SecondaryColor => secondaryColor;
public float CurrentAlpha => _currentAlpha;
private void Awake()
{
InitializeLineRenderer();
SetupGlowPoint();
InitializeNoise();
InitializeScanLines();
}
/// <summary>
/// 响应 Inspector 中的值变化
/// </summary>
private void OnValidate()
{
// 确保在编辑器中能即时预览
if (_lineRenderer == null)
{
_lineRenderer = GetComponent<LineRenderer>();
}
if (_lineRenderer != null)
{
_lineRenderer.startWidth = lineWidth;
_lineRenderer.endWidth = lineWidth;
if (_points == null || _points.Length != resolution)
{
_points = new Vector3[resolution];
_lineRenderer.positionCount = resolution;
}
UpdateColors();
}
// 检查Config预览设置
if (previewFromConfig != ConfigPreviewType.None && previewConfig == null)
{
Debug.LogWarning("WaveformRenderer: 请先拖入 WaveformConfig 资源到 Preview Config 字段!");
}
// 强制刷新按钮
if (forceRefresh)
{
forceRefresh = false;
InitializeNoise();
// 显示实际使用的参数
if (previewFromConfig != ConfigPreviewType.None && previewConfig != null)
{
var settings = GetPreviewSettings();
if (settings != null)
{
Debug.Log($"WaveformRenderer: 预览Config [{previewFromConfig}] - 类型:{settings.waveType}, 高度:{settings.waveHeight}, 速度:{settings.waveSpeed}, 频率:{settings.frequency}");
}
}
else
{
Debug.Log($"WaveformRenderer: 使用本地参数 - 类型:{waveType}, 高度:{waveHeight}, 速度:{waveSpeed}, 频率:{frequency}");
}
}
if (_noiseSeed == null || _noiseSeed.Length != resolution)
{
InitializeNoise();
}
// 在编辑器中立即更新波形
if (!Application.isPlaying)
{
UpdateWaveform();
}
}
private void InitializeLineRenderer()
{
_lineRenderer = GetComponent<LineRenderer>();
if (_lineRenderer == null) return;
_lineRenderer.useWorldSpace = false;
_lineRenderer.positionCount = resolution;
_lineRenderer.startWidth = lineWidth;
_lineRenderer.endWidth = lineWidth;
_points = new Vector3[resolution];
UpdateColors();
}
private void InitializeNoise()
{
_noiseSeed = new float[resolution];
for (int i = 0; i < resolution; i++)
{
_noiseSeed[i] = Random.Range(0f, 100f);
}
}
private void SetupGlowPoint()
{
if (!showGlowPoint) return;
if (glowPointRenderer == null)
{
GameObject glowObj = new GameObject("GlowPoint");
glowObj.transform.SetParent(transform);
glowObj.transform.localPosition = Vector3.zero;
glowPointRenderer = glowObj.AddComponent<SpriteRenderer>();
Texture2D texture = new Texture2D(32, 32);
Color[] colors = new Color[32 * 32];
for (int i = 0; i < colors.Length; i++)
{
float x = (i % 32) / 31f;
float y = (i / 32) / 31f;
float distance = Vector2.Distance(new Vector2(x, y), new Vector2(0.5f, 0.5f));
colors[i] = new Color(1, 1, 1, Mathf.Clamp01(1 - distance * 2));
}
texture.SetPixels(colors);
texture.Apply();
Sprite sprite = Sprite.Create(texture, new Rect(0, 0, 32, 32), new Vector2(0.5f, 0.5f));
glowPointRenderer.sprite = sprite;
}
glowPointRenderer.color = primaryColor;
glowPointRenderer.transform.localScale = Vector3.one * glowSize;
}
private void Update()
{
if (_lineRenderer == null) InitializeLineRenderer();
if (_points == null) _points = new Vector3[resolution];
if (_noiseSeed == null) InitializeNoise();
// 获取实际波形速度(优先使用Config预览)
float actualWaveSpeed = waveSpeed;
bool isEditor = !Application.isPlaying;
if (isEditor && previewFromConfig != ConfigPreviewType.None && previewConfig != null)
{
WaveformSettings settings = GetPreviewSettings();
if (settings != null)
{
actualWaveSpeed = settings.waveSpeed;
}
}
_phaseOffset += Time.deltaTime * actualWaveSpeed;
_noisePhase += Time.deltaTime * noiseSpeed;
// 轻微“电源纹波/亮度呼吸”,用于提升拟真仪表屏质感
if (enableOscilloscopeArtifacts && Application.isPlaying)
{
// 使用低成本噪声 + 50Hz正弦混合,避免过于规律
float t = Time.time;
float hum = Mathf.Sin(t * Mathf.PI * 2f * crtHumHz) * 0.5f + 0.5f; // 0..1
float rand = Mathf.PerlinNoise(t * 4.2f, 0.13f); // 0..1
float mix = Mathf.Lerp(hum, rand, 0.6f); // 0..1
_crtAlphaMul = Mathf.Clamp(1f - crtFlickerAmount + mix * crtFlickerAmount * 2f, 0.7f, 1.15f);
}
else
{
_crtAlphaMul = 1f;
}
UpdateWaveform();
}
private void UpdateWaveform()
{
if (_lineRenderer == null || _points == null) return;
// 确定当前使用的预览模式
bool isEditor = !Application.isPlaying;
PreviewMode currentMode = isEditor ? editorPreviewMode : PreviewMode.Runtime;
// 获取实际使用的参数(优先使用Config预览)
WaveformType actualWaveType = waveType;
float actualFrequency = frequency;
float actualWaveHeight = waveHeight;
float actualWaveSpeed = waveSpeed;
if (isEditor && previewFromConfig != ConfigPreviewType.None && previewConfig != null)
{
WaveformSettings settings = GetPreviewSettings();
if (settings != null)
{
actualWaveType = settings.waveType;
actualFrequency = settings.frequency;
actualWaveHeight = settings.waveHeight;
actualWaveSpeed = settings.waveSpeed;
}
}
for (int i = 0; i < resolution; i++)
{
float x = ((float)i / resolution) * waveWidth - waveWidth * 0.5f;
float normalizedX = (float)i / resolution;
float timeOffset = normalizedX * actualFrequency + _phaseOffset;
// 获取基础波形值
float baseWaveValue;
if (_isTransforming)
{
baseWaveValue = GetTransformingWaveValue(timeOffset, normalizedX);
}
else
{
baseWaveValue = GetWaveValue(actualWaveType, timeOffset, normalizedX);
}
float finalValue;
switch (currentMode)
{
case PreviewMode.Clean:
// 清晰模式:直接显示波形
finalValue = baseWaveValue;
break;
case PreviewMode.WithNoise:
// 噪波模式:只显示噪波效果,不考虑清晰度
float noise = GenerateNoise(i, normalizedX);
finalValue = Mathf.Lerp(noise, baseWaveValue, 1f - noiseAmount);
break;
case PreviewMode.Runtime:
default:
// 运行时模式:应用噪波和清晰度
float localClarity = CalculateLocalClarity(normalizedX);
float runtimeNoise = GenerateNoise(i, normalizedX);
finalValue = Mathf.Lerp(runtimeNoise, baseWaveValue, localClarity);
break;
}
// 复古示波器:给“非清晰区域”加一点点垂直抖动(更像硬件采样/显示抖动)
if (enableOscilloscopeArtifacts && Application.isPlaying && currentMode == PreviewMode.Runtime)
{
float localClarity = CalculateLocalClarity(normalizedX);
float jitterMask = Mathf.Clamp01(1f - localClarity);
float n = (Mathf.PerlinNoise(_noisePhase * 1.7f, normalizedX * 8.0f) - 0.5f) * 2f; // -1..1
float hum = Mathf.Sin((Time.time * crtHumHz + normalizedX * 3.5f) * Mathf.PI * 2f); // -1..1
float jitter = (n * 0.7f + hum * 0.3f) * crtVerticalJitter * jitterMask;
finalValue += jitter;
}
_points[i] = new Vector3(x, finalValue * actualWaveHeight, 0f);
}
_lineRenderer.SetPositions(_points);
UpdateLineColors();
if (showGlowPoint && glowPointRenderer != null && resolution > 0)
{
glowPointRenderer.transform.localPosition = _points[resolution - 1];
}
}
/// <summary>
/// 获取当前预览的Config设置
/// </summary>
private WaveformSettings GetPreviewSettings()
{
if (previewConfig == null) return null;
switch (previewFromConfig)
{
case ConfigPreviewType.Emotion:
return previewConfig.emotionWaveform;
case ConfigPreviewType.Logic:
return previewConfig.logicWaveform;
case ConfigPreviewType.Joke:
return previewConfig.jokeWaveform;
case ConfigPreviewType.FilterOutput:
return previewConfig.filterOutputWaveform;
case ConfigPreviewType.NormalOutput:
return previewConfig.normalOutputWaveform;
default:
return null;
}
}
/// <summary>
/// 计算指定位置的局部清晰度
/// </summary>
private float CalculateLocalClarity(float normalizedX)
{
// 基础清晰度
float baseClarity = clarity;
// 如果清晰度大于0,在清晰位置附近更清晰
if (clarity > 0)
{
float distanceFromClear = Mathf.Abs(normalizedX - clarityPosition);
float clearZone = 1f - Mathf.Clamp01(distanceFromClear / clarityWidth);
baseClarity = Mathf.Max(clarity, clearZone);
}
return Mathf.Clamp01(baseClarity);
}
/// <summary>
/// 生成噪波(像录音软件中的声波)
/// </summary>
private float GenerateNoise(int index, float normalizedX)
{
float seed = _noiseSeed[index];
// 多层噪波叠加,产生声波效果
float noise = 0f;
// 低频噪波 - 整体起伏
noise += Mathf.PerlinNoise(seed + _noisePhase * 0.3f, normalizedX * 2f) * 0.6f;
// 中频噪波 - 细节
noise += Mathf.PerlinNoise(seed * 2f + _noisePhase * 0.7f, normalizedX * 5f) * 0.3f;
// 高频噪波 - 毛刺
noise += (Mathf.PerlinNoise(seed * 3f + _noisePhase, normalizedX * noiseFrequency) - 0.5f) * 0.4f;
// 随机尖峰(像声波的峰值)
float spike = Mathf.Sin((normalizedX + _noisePhase * 0.1f) * Mathf.PI * 20f);
spike = Mathf.Pow(Mathf.Abs(spike), 3f) * Mathf.Sign(spike);
noise += spike * 0.2f;
// 归一化到 -1 到 1
noise = (noise - 0.5f) * 2f * noiseAmount;
return Mathf.Clamp(noise, -1f, 1f);
}
/// <summary>
/// 更新线条颜色(清晰区域显示高亮的主色调)
/// </summary>
private void UpdateLineColors()
{
if (_lineRenderer == null) return;
Gradient gradient = new Gradient();
float effectiveAlpha = Mathf.Clamp01(_currentAlpha * _crtAlphaMul);
if (clarity > 0.5f)
{
// 有清晰区域时,显示清晰位置的颜色变化
float clearStart = Mathf.Clamp01(clarityPosition - clarityWidth);
float clearEnd = Mathf.Clamp01(clarityPosition + clarityWidth);
// 使用高亮的主色调作为清晰区域颜色(不再使用绿色)
Color brightenedColor = GetBrightenedClearColor();
gradient.SetKeys(
new GradientColorKey[] {
new GradientColorKey(primaryColor, 0f),
new GradientColorKey(primaryColor, clearStart),
new GradientColorKey(brightenedColor, clarityPosition),
new GradientColorKey(primaryColor, clearEnd),
new GradientColorKey(secondaryColor, 1f)
},
new GradientAlphaKey[] {
new GradientAlphaKey(effectiveAlpha, 0f),
new GradientAlphaKey(effectiveAlpha, 1f)
}
);
}
else
{
gradient.SetKeys(
new GradientColorKey[] {
new GradientColorKey(primaryColor, 0f),
new GradientColorKey(secondaryColor, 1f)
},
new GradientAlphaKey[] {
new GradientAlphaKey(effectiveAlpha, 0f),
new GradientAlphaKey(effectiveAlpha, 1f)
}
);
}
_lineRenderer.colorGradient = gradient;
}
/// <summary>
/// 获取高亮的清晰区域颜色(基于主色调)
/// </summary>
private Color GetBrightenedClearColor()
{
if (!useBrightenedClearColor)
{
return primaryColor;
}
// 将主色调提亮
Color.RGBToHSV(primaryColor, out float h, out float s, out float v);
v = Mathf.Clamp01(v + clearColorBrighten);
s = Mathf.Clamp01(s * 0.8f); // 稍微降低饱和度使其更亮
Color brightened = Color.HSVToRGB(h, s, v);
brightened.a = primaryColor.a;
return brightened;
}
private float GetWaveValue(WaveformType type, float time, float normalizedX)
{
switch (type)
{
case WaveformType.Emotion:
return GenerateEmotionWave(time, normalizedX);
case WaveformType.Logic:
return GenerateLogicWave(time);
case WaveformType.Joke:
return GenerateJokeWave(time, normalizedX);
case WaveformType.FilterOutput:
return GenerateFilterOutput(time, normalizedX);
case WaveformType.NormalOutput:
return GenerateNormalOutput(time, normalizedX);
default:
return Mathf.Sin(time * Mathf.PI * 2f);
}
}
#region 波形生成
/// <summary>
/// 情绪波形 - 基于谐波叠加的简洁实现
/// 采用傅里叶合成:基波 + 二次谐波 + 三次谐波
/// 特征:低频、缓慢、通过谐波叠加表达悲伤/压抑情绪
/// 谐波参数可通过 WaveformSettings 配置
/// </summary>
private float GenerateEmotionWave(float time, float normalizedX)
{
// 慢速时间,体现低沉感
float slowTime = time * 0.4f;
float t = slowTime * Mathf.PI * 2f; // 基频角度
// 傅里叶合成:基波 + 二次谐波 + 三次谐波(使用可配置参数)
float fundamental = Mathf.Sin(t) * _harmonicA1; // 基波
float harmonic2 = Mathf.Sin(2f * t + _harmonicPhase2) * _harmonicA2; // 二次谐波
float harmonic3 = Mathf.Sin(3f * t + _harmonicPhase3) * _harmonicA3; // 三次谐波
// 叠加得到最终波形
float result = fundamental + harmonic2 + harmonic3;
// 整体偏移(负值表示下沉,体现压抑感)
result += _verticalOffset;
return Mathf.Clamp(result, -1f, 1f);
}
/// <summary>
/// 逻辑波形 - 清晰的方波
/// </summary>
private float GenerateLogicWave(float time)
{
float t = time % 1f;
if (t < 0) t += 1f;
float amplitude = 0.7f;
float squareWave = t < 0.5f ? amplitude : -amplitude;
// 非常短的边缘过渡
float edgeSmooth = 0.015f;
if (t < edgeSmooth)
{
squareWave = Mathf.Lerp(-amplitude, amplitude, t / edgeSmooth);
}
else if (t > 0.5f - edgeSmooth && t < 0.5f + edgeSmooth)
{
float localT = (t - (0.5f - edgeSmooth)) / (edgeSmooth * 2f);
squareWave = Mathf.Lerp(amplitude, -amplitude, localT);
}
else if (t > 1f - edgeSmooth)
{
squareWave = Mathf.Lerp(-amplitude, amplitude, (t - (1f - edgeSmooth)) / edgeSmooth);
}
return squareWave;
}
/// <summary>
/// 笑话波形 - 高频、尖锐、跳动
/// 特征:快速的脉冲、突然的尖峰、亢奋的跳动
/// </summary>
private float GenerateJokeWave(float time, float normalizedX)
{
// 使用更快的时间,让波形看起来更尖锐跳动
float fastTime = time * 2.5f; // 快2.5倍
float t = fastTime % 1f;
if (t < 0) t += 1f;
// 快速三角脉冲(尖锐的笑声节奏)
float pulsePhase = (t * 4f) % 1f; // 每周期4个脉冲
float pulse = 0f;
if (pulsePhase < 0.1f)
{
// 非常快速的上升
pulse = pulsePhase / 0.1f;
}
else if (pulsePhase < 0.2f)
{
// 快速下降
pulse = 1f - (pulsePhase - 0.1f) / 0.1f;
}
pulse *= 0.9f;
// 高频振荡(尖锐感)
float highFreq = Mathf.Sin(t * Mathf.PI * 12f) * 0.35f;
// 随机尖峰(突然的"笑点"爆发)
float spike = 0f;
float spikeT = (t * 7f) % 1f;
if (spikeT < 0.08f)
{
spike = Mathf.Sin(spikeT / 0.08f * Mathf.PI) * 0.5f;
}
// 额外的高频颤动(亢奋感)
float tremor = Mathf.Sin(t * Mathf.PI * 25f + normalizedX * 5f) * 0.12f;
float result = pulse + highFreq + spike + tremor;
return Mathf.Clamp(result, -1f, 1f);
}
private float GenerateFilterOutput(float time, float normalizedX)
{
float logic = GenerateLogicWave(time);
float joke = GenerateJokeWave(time, normalizedX);
float effectiveLogicWeight = _logicWeight;
float effectiveJokeWeight = _jokeWeight * _synthesisProgress;
float result = logic * effectiveLogicWeight + joke * effectiveJokeWeight;
return Mathf.Clamp(result, -1f, 1f);
}
private float GenerateNormalOutput(float time, float normalizedX)
{
float logic = GenerateLogicWave(time) * 0.4f;
float emotion = GenerateEmotionWave(time, normalizedX) * 0.4f;
float result = logic + emotion;
result += Mathf.Sin(time * Mathf.PI * 3f) * 0.1f;
return Mathf.Clamp(result, -1f, 1f);
}
#endregion
#region 公共方法
/// <summary>
/// 设置清晰度(0=完全噪波, 1=完全清晰)
/// </summary>
public void SetClarity(float value)
{
clarity = Mathf.Clamp01(value);
}
/// <summary>
/// 设置清晰位置(进度条位置,0-1)
/// </summary>
public void SetClarityPosition(float position)
{
clarityPosition = Mathf.Clamp01(position);
}
/// <summary>
/// 设置清晰区域宽度
/// </summary>
public void SetClarityWidth(float width)
{
clarityWidth = Mathf.Clamp(width, 0.01f, 0.5f);
}
/// <summary>
/// 设置噪波强度
/// </summary>
public void SetNoiseAmount(float amount)
{
noiseAmount = Mathf.Clamp01(amount);
}
/// <summary>
/// 检查当前位置是否清晰(用于锁定检测)
/// </summary>
public bool IsPositionClear(float position, float threshold = 0.8f)
{
float localClarity = CalculateLocalClarity(position);
return localClarity >= threshold;
}
public void ApplySettings(WaveformSettings settings)
{
waveType = settings.waveType;
waveHeight = settings.waveHeight;
waveSpeed = settings.waveSpeed;
frequency = settings.frequency;
primaryColor = settings.primaryColor;
secondaryColor = settings.secondaryColor;
// 应用谐波配置(用于情绪波形的傅里叶合成)
_harmonicA1 = settings.harmonicA1;
_harmonicA2 = settings.harmonicA2;
_harmonicA3 = settings.harmonicA3;
_harmonicPhase2 = settings.harmonicPhase2;
_harmonicPhase3 = settings.harmonicPhase3;
_verticalOffset = settings.verticalOffset;
UpdateColors();
}
public void SetWaveType(WaveformType type)
{
waveType = type;
_isTransforming = false;
}
public void SetColors(Color primary, Color secondary)
{
primaryColor = primary;
secondaryColor = secondary;
UpdateColors();
}
public void StartTransform(WaveformType fromType, WaveformType toType)
{
_transformFromType = fromType;
_transformToType = toType;
_transformProgress = 0f;
_transformDistortion = 0f;
_transformCompression = 1f;
_isTransforming = true;
}
public void UpdateTransformProgress(float progress)
{
_transformProgress = Mathf.Clamp01(progress);
// 计算变换过程中的效果参数
// 0-0.3: 开始扭曲,波形开始不稳定
// 0.3-0.7: 最大扭曲+压缩,波形被"挤压"
// 0.7-1.0: 扭曲消退,新波形稳定
if (_transformProgress < 0.3f)
{
float t = _transformProgress / 0.3f;
_transformDistortion = Mathf.Sin(t * Mathf.PI) * 0.5f;
_transformCompression = 1f;
}
else if (_transformProgress < 0.7f)
{
float t = (_transformProgress - 0.3f) / 0.4f;
_transformDistortion = 0.5f + Mathf.Sin(t * Mathf.PI * 3f) * 0.3f;
// 压缩效果:低频被压缩成高频的感觉
_transformCompression = Mathf.Lerp(1f, 2.5f, t);
}
else
{
float t = (_transformProgress - 0.7f) / 0.3f;
_transformDistortion = Mathf.Lerp(0.5f, 0f, t);
_transformCompression = Mathf.Lerp(2.5f, 1f, t);
}
if (_transformProgress >= 1f)
{
waveType = _transformToType;
_isTransforming = false;
_transformDistortion = 0f;
_transformCompression = 1f;
}
}
public void FinishTransform()
{
waveType = _transformToType;
_transformProgress = 1f;
_isTransforming = false;
_transformDistortion = 0f;
_transformCompression = 1f;
}
/// <summary>
/// 获取变换过程中的波形值(带有戏剧性的过渡效果)
/// </summary>
private float GetTransformingWaveValue(float timeOffset, float normalizedX)
{
float fromValue = GetWaveValue(_transformFromType, timeOffset, normalizedX);
float toValue = GetWaveValue(_transformToType, timeOffset * _transformCompression, normalizedX);
// 基础混合
float blendedValue = Mathf.Lerp(fromValue, toValue, _transformProgress);
// 添加扭曲效果(波形被挤压、扭曲的感觉)
if (_transformDistortion > 0)
{
// 添加不规则的高频扰动
float distortion = Mathf.Sin(timeOffset * 15f + normalizedX * 10f) * _transformDistortion;
distortion += Mathf.Sin(timeOffset * 23f) * _transformDistortion * 0.5f;
// 压缩效果:让波形看起来像是被挤压
float compressionEffect = Mathf.Sin(normalizedX * Mathf.PI * _transformCompression * 2f) * _transformDistortion * 0.3f;
blendedValue += distortion + compressionEffect;
}
return Mathf.Clamp(blendedValue, -1.2f, 1.2f); // 允许稍微超出范围增加戏剧感
}
public void SetSynthesisWeights(float logicWeight, float jokeWeight)
{
_logicWeight = Mathf.Clamp01(logicWeight);
_jokeWeight = Mathf.Clamp01(jokeWeight);
}
public void SetSynthesisProgress(float progress)
{
_synthesisProgress = Mathf.Clamp01(progress);
}
public void SetVisible(bool visible)
{
if (_lineRenderer != null)
_lineRenderer.enabled = visible;
if (glowPointRenderer != null)
glowPointRenderer.enabled = visible;
}
public void SetAlpha(float alpha)
{
_currentAlpha = Mathf.Clamp01(alpha);
if (_lineRenderer == null) return;
Color startColor = primaryColor;
Color endColor = secondaryColor;
startColor.a = _currentAlpha;
endColor.a = _currentAlpha;
Gradient gradient = new Gradient();
gradient.SetKeys(
new GradientColorKey[] { new GradientColorKey(startColor, 0f), new GradientColorKey(endColor, 1f) },
new GradientAlphaKey[] { new GradientAlphaKey(_currentAlpha, 0f), new GradientAlphaKey(_currentAlpha, 1f) }
);
_lineRenderer.colorGradient = gradient;
if (glowPointRenderer != null)
{
Color glowColor = primaryColor;
glowColor.a = _currentAlpha;
glowPointRenderer.color = glowColor;
}
}
private void UpdateColors()
{
if (_lineRenderer == null) return;
// 获取实际颜色(优先使用Config预览)
Color actualPrimaryColor = primaryColor;
Color actualSecondaryColor = secondaryColor;
bool isEditor = !Application.isPlaying;
if (isEditor && previewFromConfig != ConfigPreviewType.None && previewConfig != null)
{
WaveformSettings settings = GetPreviewSettings();
if (settings != null)
{
actualPrimaryColor = settings.primaryColor;
actualSecondaryColor = settings.secondaryColor;
}
}
Gradient gradient = new Gradient();
gradient.SetKeys(
new GradientColorKey[] { new GradientColorKey(actualPrimaryColor, 0f), new GradientColorKey(actualSecondaryColor, 1f) },
new GradientAlphaKey[] { new GradientAlphaKey(_currentAlpha, 0f), new GradientAlphaKey(_currentAlpha, 1f) }
);
_lineRenderer.colorGradient = gradient;
if (glowPointRenderer != null)
{
glowPointRenderer.color = actualPrimaryColor;
}
}
#endregion
#region 扫描线系统
/// <summary>
/// 初始化扫描线
/// </summary>
private void InitializeScanLines()
{
// 确保主LineRenderer已初始化
if (_lineRenderer == null)
{
_lineRenderer = GetComponent<LineRenderer>();
}
// 计算扫描线宽度(相对于波形线宽,更细一点)
float scanWidth = lineWidth * scanLineWidthMultiplier;
float limitWidth = lineWidth * limitLineWidthMultiplier;
// 创建垂直扫描线(用于屏蔽词检测)
_scanLineRenderer = CreateScanLineRenderer("ScanLine", scanLineColor, scanWidth);
if (_scanLineRenderer != null) _scanLineRenderer.gameObject.SetActive(false);
// 创建上限线(用于限幅检测)
_upperLimitLineRenderer = CreateScanLineRenderer("UpperLimitLine", limitLineColor, limitWidth);
if (_upperLimitLineRenderer != null) _upperLimitLineRenderer.gameObject.SetActive(false);
// 创建下限线(用于限幅检测)
_lowerLimitLineRenderer = CreateScanLineRenderer("LowerLimitLine", limitLineColor, limitWidth);
if (_lowerLimitLineRenderer != null) _lowerLimitLineRenderer.gameObject.SetActive(false);
Debug.Log($"WaveformRenderer: 扫描线初始化完成 - ScanLine:{_scanLineRenderer != null}, UpperLimit:{_upperLimitLineRenderer != null}, LowerLimit:{_lowerLimitLineRenderer != null}, ScanWidth:{scanWidth:F4}, LimitWidth:{limitWidth:F4}");
}
private LineRenderer CreateScanLineRenderer(string name, Color color, float width)
{
GameObject lineObj = new GameObject(name);
lineObj.transform.SetParent(transform);
lineObj.transform.localPosition = Vector3.zero;
lineObj.transform.localScale = Vector3.one;
LineRenderer lr = lineObj.AddComponent<LineRenderer>();
// 使用主LineRenderer的材质,或者创建一个简单的材质
if (_lineRenderer != null && _lineRenderer.material != null)
{
lr.material = new Material(_lineRenderer.material);
}
else
{
// 回退方案:使用内置的UI shader
Shader shader = Shader.Find("UI/Default");
if (shader == null) shader = Shader.Find("Sprites/Default");
if (shader == null) shader = Shader.Find("Unlit/Color");
lr.material = new Material(shader);
}
lr.startColor = color;
lr.endColor = color;
lr.startWidth = width;
lr.endWidth = width;
lr.positionCount = 2;
lr.useWorldSpace = false;
// 设置层级:Tools层 + offset
lr.sortingLayerName = scanLineSortingLayer;
lr.sortingOrder = scanLineSortingOrderOffset;
return lr;
}
/// <summary>
/// 显示垂直扫描线在指定位置
/// </summary>
public void ShowScanLine(float normalizedX, float height = -1f)
{
if (_scanLineRenderer == null)
{
Debug.LogWarning("WaveformRenderer: 扫描线未初始化!尝试重新初始化...");
InitializeScanLines();
if (_scanLineRenderer == null) return;
}
float actualHeight = height > 0 ? height : waveHeight * 1.5f;
float xPos = (normalizedX - 0.5f) * waveWidth;
_scanLineRenderer.SetPosition(0, new Vector3(xPos, -actualHeight, 0));
_scanLineRenderer.SetPosition(1, new Vector3(xPos, actualHeight, 0));
_scanLineRenderer.gameObject.SetActive(true);
Debug.Log($"WaveformRenderer: 显示扫描线 - X:{xPos:F2}, Height:{actualHeight:F2}, WaveWidth:{waveWidth}, WaveHeight:{waveHeight}");
}
/// <summary>
/// 隐藏垂直扫描线
/// </summary>
public void HideScanLine()
{
if (_scanLineRenderer != null)
{
_scanLineRenderer.gameObject.SetActive(false);
}
}
/// <summary>
/// 设置扫描线位置(用于动画)
/// </summary>
public void SetScanLinePosition(float normalizedX)
{
if (_scanLineRenderer == null || !_scanLineRenderer.gameObject.activeSelf) return;
float xPos = (normalizedX - 0.5f) * waveWidth;
Vector3 pos0 = _scanLineRenderer.GetPosition(0);
Vector3 pos1 = _scanLineRenderer.GetPosition(1);
_scanLineRenderer.SetPosition(0, new Vector3(xPos, pos0.y, 0));
_scanLineRenderer.SetPosition(1, new Vector3(xPos, pos1.y, 0));
}
/// <summary>
/// 显示限幅线(上下限)
/// </summary>
public void ShowLimitLines(float upperLimit = -1f, float lowerLimit = -1f)
{
if (_upperLimitLineRenderer == null || _lowerLimitLineRenderer == null)
{
Debug.LogWarning("WaveformRenderer: 限幅线未初始化!尝试重新初始化...");
InitializeScanLines();
if (_upperLimitLineRenderer == null || _lowerLimitLineRenderer == null) return;
}
float actualUpper = upperLimit > 0 ? upperLimit : waveHeight * 0.8f;
float actualLower = lowerLimit > 0 ? lowerLimit : -waveHeight * 0.8f;
float halfWidth = waveWidth * 0.5f;
// 上限线
_upperLimitLineRenderer.SetPosition(0, new Vector3(-halfWidth, actualUpper, 0));
_upperLimitLineRenderer.SetPosition(1, new Vector3(halfWidth, actualUpper, 0));
_upperLimitLineRenderer.gameObject.SetActive(true);
// 下限线
_lowerLimitLineRenderer.SetPosition(0, new Vector3(-halfWidth, actualLower, 0));
_lowerLimitLineRenderer.SetPosition(1, new Vector3(halfWidth, actualLower, 0));
_lowerLimitLineRenderer.gameObject.SetActive(true);
Debug.Log($"WaveformRenderer: 显示限幅线 - Upper:{actualUpper:F2}, Lower:{actualLower:F2}, Width:{halfWidth * 2:F2}");
}
/// <summary>
/// 隐藏限幅线
/// </summary>
public void HideLimitLines()
{
if (_upperLimitLineRenderer != null)
{
_upperLimitLineRenderer.gameObject.SetActive(false);
}
if (_lowerLimitLineRenderer != null)
{
_lowerLimitLineRenderer.gameObject.SetActive(false);
}
}
/// <summary>
/// 设置限幅线透明度(用于闪烁动画)
/// </summary>
public void SetLimitLinesAlpha(float alpha)
{
Color color = limitLineColor;
color.a = alpha;
if (_upperLimitLineRenderer != null)
{
_upperLimitLineRenderer.startColor = color;
_upperLimitLineRenderer.endColor = color;
}
if (_lowerLimitLineRenderer != null)
{
_lowerLimitLineRenderer.startColor = color;
_lowerLimitLineRenderer.endColor = color;
}
}
/// <summary>
/// 设置扫描线颜色
/// </summary>
public void SetScanLineColor(Color color)
{
if (_scanLineRenderer != null)
{
_scanLineRenderer.startColor = color;
_scanLineRenderer.endColor = color;
}
}
#endregion
}
}