Files
aibis-dream/Assets/Scripts/FixSystem/Scope/WaveformVisualizer.cs
T

269 lines
7.7 KiB
C#

using UnityEngine;
using System.Collections;
using DG.Tweening;
[RequireComponent(typeof(LineRenderer))]
public class WaveformVisualizer : MonoBehaviour
{
public int samples = 1024;
public float amplitude = 1f;
public float spatialFrequency = 1f;
public float temporalFrequency = 0.1f;
public float noiseAmplitude = 0.5f;
public float targetWaveformNoiseAmplitude = 0f;
[Range(0f, 1f)]
public float clarity = 0f;
public Color noiseColor = Color.gray;
public Color clearColor = Color.green;
private LineRenderer lineRenderer;
private SpriteRenderer spriteRenderer;
private float spriteWidth;
private float spriteHeight;
private float[] waveformData;
private float[] noiseData;
private float[] displayData;
public WaveformType waveformType = WaveformType.Sine;
public float amplitudeModulationFrequency = 0.5f;
public float amplitudeModulationDepth = 0.5f;
private bool isShaking = false;
private bool isDisordered = false;
public float shakeDuration = 0.5f;
public float disorderDuration = 1f;
public float shakeAmount = 0.1f;
private Coroutine shockCoroutine;
private Color originalWaveColor;
void Start()
{
lineRenderer = GetComponent<LineRenderer>();
lineRenderer.positionCount = samples;
lineRenderer.useWorldSpace = false;
spriteRenderer = GetComponentInParent<SpriteRenderer>();
if (spriteRenderer != null)
{
spriteWidth = spriteRenderer.bounds.size.x;
spriteHeight = spriteRenderer.bounds.size.y;
lineRenderer.sortingLayerID = spriteRenderer.sortingLayerID;
lineRenderer.sortingOrder = spriteRenderer.sortingOrder + 1;
}
else
{
Debug.LogError("Could not find SpriteRenderer in parent object.");
}
waveformData = new float[samples];
noiseData = new float[samples];
displayData = new float[samples];
originalWaveColor = Color.Lerp(noiseColor, clearColor, clarity);
}
void Update()
{
if (isDisordered)
{
GenerateDisorderedData();
}
else
{
GenerateNoiseData();
GenerateWaveformData();
for (int i = 0; i < samples; i++)
{
displayData[i] = Mathf.Lerp(noiseData[i], waveformData[i], clarity);
}
SmoothWaveform(displayData, 2);
}
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);
}
}
float GetWaveformValue(float t)
{
float time = Time.time * temporalFrequency;
float amplitudeModulation = 1f + amplitudeModulationDepth * Mathf.Sin(2f * Mathf.PI * amplitudeModulationFrequency * Time.time);
float angle = t * Mathf.PI * 2f * spatialFrequency + time;
float value = 0f;
switch (waveformType)
{
case WaveformType.Sine:
value = Mathf.Sin(angle);
break;
case WaveformType.Square:
value = Mathf.Sign(Mathf.Sin(angle));
break;
case WaveformType.Triangle:
value = Mathf.PingPong(angle / Mathf.PI, 2f) - 1f;
break;
case WaveformType.Sawtooth:
value = ((angle / (Mathf.PI * 2f)) % 1f) * 2f - 1f;
break;
case WaveformType.Pulse:
value = Mathf.PingPong(angle / Mathf.PI, 2f) > 1f ? 1f : -1f;
break;
case WaveformType.Noise:
value = Mathf.PerlinNoise(angle / (Mathf.PI * 2f), Time.time * temporalFrequency) * 2f - 1f;
break;
case WaveformType.Composite:
value = Mathf.Sin(angle) + Mathf.Sin(angle * 2f) * 0.5f;
break;
}
return value * amplitude * amplitudeModulation;
}
void GenerateDisorderedData()
{
for (int i = 0; i < samples; i++)
{
displayData[i] = Random.Range(-amplitude, amplitude);
}
SmoothWaveform(displayData, 2);
}
void DrawWaveform()
{
for (int i = 0; i < samples; i++)
{
float x = ((float)i / (samples - 1)) * spriteWidth - (spriteWidth / 2f);
float amplitudeScale = Mathf.Lerp(0.2f, 1f, clarity);
float y = displayData[i] * amplitudeScale * (spriteHeight / 2f);
Vector3 position = new Vector3(x, y, 0);
if (isShaking)
{
float offsetX = Random.Range(-shakeAmount, shakeAmount);
float offsetY = Random.Range(-shakeAmount, shakeAmount);
position += new Vector3(offsetX, offsetY, 0);
}
lineRenderer.SetPosition(i, position);
}
Color waveColor = Color.Lerp(noiseColor, clearColor, clarity);
if (isDisordered)
{
waveColor = Color.red;
}
lineRenderer.startColor = waveColor;
lineRenderer.endColor = waveColor;
float startWidth = Mathf.Lerp(0.02f, 0.05f, clarity);
lineRenderer.startWidth = startWidth;
lineRenderer.endWidth = startWidth;
}
void SmoothWaveform(float[] data, int iterations)
{
for (int iter = 0; iter < iterations; iter++)
{
float prev = data[0];
for (int i = 1; i < data.Length - 1; i++)
{
float current = data[i];
data[i] = (prev + current + data[i + 1]) / 3f;
prev = current;
}
}
}
public void TriggerShock(bool isCorrect)
{
if (shockCoroutine != null)
{
StopCoroutine(shockCoroutine);
}
shockCoroutine = StartCoroutine(ShockRoutine(isCorrect));
}
IEnumerator ShockRoutine(bool isCorrect)
{
if (!isCorrect)
{
isDisordered = true;
DOTween.To(() => 0f, x => ApplyDisorder(x), 1f, disorderDuration / 2)
.SetEase(Ease.InOutSine);
yield return new WaitForSeconds(disorderDuration);
DOTween.To(() => 1f, x => ApplyDisorder(x), 0f, disorderDuration / 2)
.SetEase(Ease.InOutSine)
.OnComplete(() => isDisordered = false);
}
else
{
isShaking = true;
DOTween.To(() => shakeAmount, x => shakeAmount = x, 0.1f, shakeDuration / 2)
.SetEase(Ease.InOutSine)
.OnComplete(() =>
{
DOVirtual.DelayedCall(0.5f, () =>
{
DOTween.To(() => shakeAmount, x => shakeAmount = x, 0f, shakeDuration / 2)
.SetEase(Ease.InOutSine)
.OnComplete(() => isShaking = false);
});
});
}
}
void ApplyDisorder(float progress)
{
for (int i = 0; i < samples; i++)
{
float noise = Random.Range(-amplitude * 0.1f, amplitude * 0.1f);
displayData[i] = Mathf.Lerp(waveformData[i], waveformData[i] + noise, progress);
}
SmoothWaveform(displayData, 2);
}
}
public enum WaveformType
{
Sine,
Square,
Triangle,
Sawtooth,
Pulse,
Noise,
Composite
}