using UnityEngine; using System.Collections.Generic; public enum WaveformType { Sine, Square, Triangle, Sawtooth, Noise, Composite, Pulse, } [RequireComponent(typeof(LineRenderer))] public class WaveformVisualizer : MonoBehaviour { [HideInInspector] public int samples = 1024; [HideInInspector] private float amplitude = 0.6f; public float spatialFrequency = 1f; public float temporalFrequency = 0.1f; private float targetWaveformNoiseAmplitude = 0.1f; public float noiseAmplitude = 0.5f; [Range(0f, 1f)] [HideInInspector] public float clarity = 0f; public Color noiseColor = Color.gray; public Color clearColor = Color.green; private LineRenderer lineRenderer; [HideInInspector] private SpriteRenderer spriteRenderer; [HideInInspector] public float spriteWidth; [HideInInspector] public float spriteHeight; [HideInInspector] public float[] waveformData; private float[] noiseData; [HideInInspector] public float[] displayData; private float[] antiWaveformData; public int SpikeIndex => spikeIndex; // 使 spikeIndex 可通过属性访问 [HideInInspector] public WaveformType waveformType = WaveformType.Sine; public float amplitudeModulationFrequency = 0.5f; public float amplitudeModulationDepth = 0.5f; public float phaseShift = 0f; // 相位偏移 private bool isCaptured = false; // 是否已拍照(冻结波形) private int spikeIndex; // 单个突刺位置 private bool isCorrect=true; private bool isSpikeIndexSet = false; // 标志位,判断 spikeIndex 是否已设置 private TargetPointData targetdata; public bool isErrorFind=false; private LineRenderer scanLineRenderer; // 新的 LineRenderer public float scanSpeed = 1f; // 扫描速度 private bool isScanning = false; // 是否正在扫描 void Start() { lineRenderer = GetComponent(); lineRenderer.positionCount = samples; lineRenderer.useWorldSpace = false; spriteRenderer = GetComponentInParent(); if (spriteRenderer != null) { spriteWidth = spriteRenderer.bounds.size.x; spriteHeight = spriteRenderer.bounds.size.y; lineRenderer.sortingLayerID = spriteRenderer.sortingLayerID; lineRenderer.sortingOrder = spriteRenderer.sortingOrder + 3; } else { Debug.LogError("Could not find SpriteRenderer in parent object."); } waveformData = new float[samples]; noiseData = new float[samples]; displayData = new float[samples]; antiWaveformData = new float[samples]; DrawWaveform(); // 初始化波形 } void Update() { GenerateNoiseData(); GenerateWaveformData(); if (phaseShift > 0) { GenerateAntiWaveformData(); } for (int i = 0; i < samples; i++) { displayData[i] = Mathf.Lerp(noiseData[i], waveformData[i], clarity); if (phaseShift > 0) { displayData[i] += antiWaveformData[i]; } if (!isCorrect) { HandleErrorDisplay(i); } displayData[i] = Mathf.Clamp(displayData[i], -spriteHeight / 1.8f, spriteHeight / 1.8f); } if(!isCorrect) { CheckError(); } DrawWaveform(); } void GenerateNoiseData() { float adjustedNoiseAmplitude = Mathf.Lerp(noiseAmplitude, targetWaveformNoiseAmplitude, clarity); for (int i = 0; i < samples; i++) { noiseData[i] = Random.Range(-adjustedNoiseAmplitude, adjustedNoiseAmplitude); } } void GenerateWaveformData() { for (int i = 0; i < samples; i++) { float t = (float)i / samples; waveformData[i] = GetWaveformValue(t, 0) * clarity; } if(!isCorrect) { GenerateErrorData(); } } private void GenerateErrorData() { if (targetdata.spikeIndex != -1) { spikeIndex = targetdata.spikeIndex; return; } if (isSpikeIndexSet) return; // 如果已设置,则不再随机 float threshold = 0.9f; // 80% 的阈值 // 找到波形数据中的最大绝对值 float maxAmplitude = 0f; for (int i = 0; i < samples; i++) { maxAmplitude = Mathf.Max(maxAmplitude, Mathf.Abs(waveformData[i])); } // 计算超过 80% 最大值的阈值 float amplitudeThreshold = maxAmplitude * threshold; // 找到所有超过阈值的点 List candidateIndices = new List(); for (int i = 0; i < samples; i++) { if (Mathf.Abs(waveformData[i]) > amplitudeThreshold) { candidateIndices.Add(i); } } // 随机选择一个满足条件的点作为 spikeIndex if (candidateIndices.Count > 0) { int randomIndex = Random.Range(0, candidateIndices.Count); spikeIndex = candidateIndices[randomIndex]; isSpikeIndexSet = true; // 标志位设为 true,表示已设置过 spikeIndex } else { spikeIndex = 0; // 如果没有找到满足条件的点,则默认为 0 isSpikeIndexSet = true; // 即使没有找到满足条件的点,也将标志位设为 true } if (targetdata != null) { targetdata.spikeIndex = spikeIndex; } } public void SetError(TargetPointData target) { isCorrect=false; targetdata=target; } float GetWaveformValue(float t, float phaseOffset) { float time = Time.time * temporalFrequency; //float amplitudeModulation = 1f + amplitudeModulationDepth * Mathf.Sin(2f * Mathf.PI * amplitudeModulationFrequency * Time.time); float angle = t * Mathf.PI * 2f * spatialFrequency + phaseOffset; float value = 0f; // 计算波形值 switch (waveformType) { case WaveformType.Sine: clearColor=Color.green; value = Mathf.Sin(angle); break; case WaveformType.Square: clearColor=Color.green; value = Mathf.Sign(Mathf.Sin(angle)); break; case WaveformType.Triangle: clearColor=Color.green; value = Mathf.PingPong(angle / Mathf.PI, 1f) * 2f - 1f; break; case WaveformType.Sawtooth: clearColor=Color.green; value = ((angle / (Mathf.PI * 2f)) % 1f) * 2f - 1f; // 统一周期为 2π break; case WaveformType.Pulse: clearColor=Color.green; value = Mathf.PingPong(angle / (Mathf.PI * 2f), 1f) > 0.5f ? 1f : -1f; // 统一周期为 2π break; case WaveformType.Noise: clearColor=Color.red; value = Mathf.PerlinNoise(angle / (Mathf.PI * 0.05f), Time.time * temporalFrequency*4) * 2f - 1f; // 统一周期为 2π break; case WaveformType.Composite: clearColor=Color.green; value = Mathf.Sin(angle) + Mathf.Sin(angle * 2f) * 0.5f; // 组合波形也统一周期 break; default: value = 0f; break; } return value * amplitude; // 最终返回波形值 //return value * amplitude * amplitudeModulation; // 最终返回波形值 } private void HandleErrorDisplay(int index) { float amplitudeScale = Mathf.Lerp(0.2f, 1f, clarity); int distanceToSpike = Mathf.Abs(spikeIndex - index); if (distanceToSpike <= 20) // 扩大扰动的半径 { float attenuation = 1f - (float)distanceToSpike / 20f; attenuation *= 0.9f; // 降低扰动强度 float baseAmplitude = displayData[index] * amplitudeScale * (spriteHeight / 2f); float randomRange = (Mathf.Abs(baseAmplitude) - amplitude / 3f) * attenuation; //isErrorFind = Mathf.Abs(baseAmplitude) < amplitude / 3; if (Mathf.Abs(baseAmplitude) < amplitude / 3) { float randomOffset = Random.Range(-randomRange, randomRange); displayData[index] += randomOffset; // 对 Y 值进行随机扰动 } //displayData[index] += Random.Range(-attenuation * 0.5f, attenuation * 0.5f); // 添加随机扰动 } } private void CheckError() { isErrorFind=displayData[spikeIndex]