Files
aibis-dream/Assets/Scripts/MiniGame/HuoShan/Language/WaveformRenderer.cs
T
2025-11-13 20:30:13 +08:00

269 lines
9.1 KiB
C#
Raw 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 UnityEngine;
using System.Collections.Generic;
using Shapes;
namespace AibisDream.MiniGame.Language
{
/// <summary>
/// 波形渲染器:使用Shapes绘制波形和交互效果
/// 注意:渲染在底层,确保低于文字(文字 sortingOrder = 10
/// </summary>
[ExecuteAlways]
public class WaveformRenderer : ImmediateModeShapeDrawer
{
[Header("波形设置")]
public Color normalWaveColor = new Color(0.59f, 0.78f, 1f, 0.8f);
public Color anxiousWaveColor = new Color(1f, 0.39f, 0.39f, 0.8f);
public float waveLineThickness = 0.04f;
public float baseY = 0f;
[Header("交互设置")]
public Color interactionColor = new Color(0.59f, 0.78f, 1f, 0.3f);
public Color interactionRingColor = new Color(0.59f, 0.78f, 1f, 0.6f);
public float interactionRadius = 0.5f;
[Header("粒子效果")]
public Color particleColor = new Color(0.59f, 0.78f, 1f, 0.8f);
private List<WaveformPoint> waveformPoints;
private CompletionPhase completionPhase;
private float calmProgress;
private Vector2 mouseWorldPos;
private bool mousePressed;
private float mouseDragSpeed;
private List<WaveformParticleEffect> waveParticles = new List<WaveformParticleEffect>();
public void SetData(
List<WaveformPoint> points,
CompletionPhase phase,
float calm,
Vector2 mousePos,
bool mouseDown,
float dragSpeed)
{
waveformPoints = points;
completionPhase = phase;
calmProgress = calm;
mouseWorldPos = mousePos;
mousePressed = mouseDown;
mouseDragSpeed = dragSpeed;
}
private void Update()
{
// 更新粒子效果
for (int i = waveParticles.Count - 1; i >= 0; i--)
{
waveParticles[i].Update(Time.deltaTime);
if (waveParticles[i].alpha <= 0 || waveParticles[i].size < 0.01f)
{
waveParticles.RemoveAt(i);
}
}
// 生成新粒子(如果正在交互)
if (mousePressed && waveformPoints != null && Random.value > 0.7f)
{
foreach (var point in waveformPoints)
{
if (point.isBeingCalmed && Random.value > 0.5f)
{
waveParticles.Add(new WaveformParticleEffect(
new Vector3(point.x, point.smoothedY, 0),
Random.Range(-0.1f, 0.1f),
Random.Range(-0.2f, -0.05f),
Random.Range(0.02f, 0.04f)
));
}
}
}
}
public override void DrawShapes(Camera cam)
{
if (waveformPoints == null || waveformPoints.Count == 0)
return;
if (completionPhase != CompletionPhase.Focusing)
return;
using (Draw.Command(cam))
{
Draw.BlendMode = ShapesBlendMode.Transparent;
Draw.ZTest = UnityEngine.Rendering.CompareFunction.Always;
// 注意:波形默认在底层,文字的 sortingOrder = 10 会显示在上层
// 绘制粒子效果
DrawWaveformParticles();
// 绘制波形线
DrawWaveformLine();
// 绘制波形点
DrawWaveformPoints();
// 绘制交互反馈
if (mousePressed)
{
DrawInteractionFeedback();
}
// 绘制基准线
if (calmProgress < 0.9f)
{
DrawBaseline();
}
}
}
private void DrawWaveformParticles()
{
foreach (var particle in waveParticles)
{
Color color = particleColor;
color.a = particle.alpha;
Draw.Disc(particle.position, particle.size, color);
// 光晕
color.a = particle.alpha * 0.3f;
Draw.Disc(particle.position, particle.size * 2f, color);
}
}
private void DrawWaveformLine()
{
Draw.LineGeometry = LineGeometry.Flat2D;
Draw.Thickness = waveLineThickness;
// 使用Polyline绘制波形
var points = new List<Vector3>();
var colors = new List<Color>();
foreach (var point in waveformPoints)
{
// 跳过完全消散的点
float dissolveProgress = point.particle != null ? point.particle.dissolveProgress : 0f;
if (dissolveProgress >= 1f) continue;
points.Add(new Vector3(point.x, point.smoothedY, 0));
// 根据抚平程度混合颜色
Color waveColor = Color.Lerp(anxiousWaveColor, normalWaveColor, point.calmAmount);
waveColor.a *= (1 - dissolveProgress);
colors.Add(waveColor);
}
if (points.Count >= 2)
{
for (int i = 0; i < points.Count - 1; i++)
{
Draw.Line(points[i], points[i + 1], colors[i], colors[i + 1]);
}
}
}
private void DrawWaveformPoints()
{
for (int i = 0; i < waveformPoints.Count; i += 3)
{
var point = waveformPoints[i];
// 跳过完全消散的点
float dissolveProgress = point.particle != null ? point.particle.dissolveProgress : 0f;
if (dissolveProgress >= 1f) continue;
Vector3 pos = new Vector3(point.x, point.smoothedY, 0);
// 如果正在被抚平,显示进度环
if (point.isBeingCalmed && point.calmTimer > 0)
{
float requiredTime = 0.5f + point.resistance * 1f;
float progress = Mathf.Min(1f, point.calmTimer / requiredTime);
Color ringColor = interactionRingColor;
ringColor.a *= (1 - dissolveProgress);
Draw.Ring(pos, 0.08f, 0.06f, ringColor);
Draw.Arc(pos, 0.08f, 0.02f, -Mathf.PI / 2f, progress * Mathf.PI * 2f, ringColor);
}
// 绘制波形点
float pointAlpha = (1 - point.calmAmount) * (1 - calmProgress * 0.5f) * (1 - dissolveProgress) * 0.6f;
if (pointAlpha > 0.05f)
{
Color pointColor = Color.Lerp(anxiousWaveColor, normalWaveColor, point.calmAmount);
pointColor.a = pointAlpha;
Draw.Disc(pos, 0.03f, pointColor);
}
}
}
private void DrawInteractionFeedback()
{
Vector3 mousePos3D = new Vector3(mouseWorldPos.x, mouseWorldPos.y, 0);
// 内圈(交互范围)
Color innerColor = interactionColor;
Draw.Disc(mousePos3D, interactionRadius, innerColor);
// 外圈(视觉反馈)
Color outerColor = interactionRingColor;
Draw.Ring(mousePos3D, interactionRadius, interactionRadius * 0.95f, outerColor);
// 根据拖动速度显示额外反馈
if (mouseDragSpeed > 0.1f)
{
Color speedColor = interactionRingColor;
speedColor.a = 0.4f;
Draw.Ring(mousePos3D, interactionRadius * 1.25f, interactionRadius * 1.2f, speedColor);
}
}
private void DrawBaseline()
{
float alpha = 0.2f * (1 - calmProgress);
Color baselineColor = normalWaveColor;
baselineColor.a = alpha;
Draw.LineGeometry = LineGeometry.Flat2D;
Draw.Thickness = 0.015f;
// 计算波形范围
if (waveformPoints.Count > 0)
{
float minX = waveformPoints[0].x;
float maxX = waveformPoints[waveformPoints.Count - 1].x;
Draw.Line(new Vector3(minX - 0.5f, baseY, 0), new Vector3(maxX + 0.5f, baseY, 0), baselineColor);
}
}
private class WaveformParticleEffect
{
public Vector3 position;
public float vx;
public float vy;
public float alpha;
public float size;
public WaveformParticleEffect(Vector3 pos, float velocityX, float velocityY, float initialSize)
{
position = pos;
vx = velocityX;
vy = velocityY;
alpha = 0.8f;
size = initialSize;
}
public void Update(float deltaTime)
{
position.x += vx * deltaTime;
position.y += vy * deltaTime;
vy += 0.1f * deltaTime; // 重力
alpha -= 0.015f;
size *= 0.98f;
}
}
}
}