269 lines
9.1 KiB
C#
269 lines
9.1 KiB
C#
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;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|