448 lines
13 KiB
C#
448 lines
13 KiB
C#
using UnityEngine;
|
|
|
|
[ExecuteInEditMode]
|
|
[RequireComponent(typeof(LineRenderer))]
|
|
public class RobotECGWave : MonoBehaviour
|
|
{
|
|
public enum WaveType
|
|
{
|
|
RobotECG,
|
|
Sine,
|
|
Triangle,
|
|
Square,
|
|
HumanECG,
|
|
Emergency,
|
|
Noise,
|
|
Abnormal,
|
|
Warning
|
|
}
|
|
|
|
[Header("波形设置")]
|
|
public WaveType waveType = WaveType.RobotECG;
|
|
|
|
public float waveHeight = 1f;
|
|
public float waveWidth = 10f;
|
|
public float waveStretch = 1f;
|
|
public float speed = 2f;
|
|
|
|
[Header("颜色设置")]
|
|
[SerializeField] private Color[] normalColors = new Color[4];
|
|
[SerializeField] private Color[] warningColors = new Color[4];
|
|
[SerializeField] private Color[] emergencyColors = new Color[4];
|
|
|
|
[Header("绘图设置")]
|
|
public int resolution = 300;
|
|
public float updateInterval = 0.02f;
|
|
|
|
[Header("发光点设置")]
|
|
public SpriteRenderer glowPoint;
|
|
public Color glowColor = Color.red;
|
|
public float glowSize = 0.1f;
|
|
|
|
[Header("噪音设置")]
|
|
public float noiseAmplitude = 0.5f;
|
|
public float targetWaveformNoiseAmplitude = 0.1f;
|
|
|
|
private LineRenderer lineRenderer;
|
|
private Vector3[] points;
|
|
private float timer = 0f;
|
|
|
|
private float lastWidth = -1f;
|
|
private int lastResolution = -1;
|
|
|
|
private float phaseOffset = 0f;
|
|
|
|
private void Start()
|
|
{
|
|
Init();
|
|
SetupGlowPoint();
|
|
}
|
|
|
|
void OnEnable()
|
|
{
|
|
Init();
|
|
}
|
|
|
|
|
|
void Init()
|
|
{
|
|
if (lineRenderer == null)
|
|
lineRenderer = GetComponent<LineRenderer>();
|
|
|
|
lineRenderer.useWorldSpace = true;
|
|
|
|
if (points == null || resolution != lastResolution || waveWidth != lastWidth)
|
|
{
|
|
points = new Vector3[resolution];
|
|
lineRenderer.positionCount = resolution;
|
|
lastResolution = resolution;
|
|
lastWidth = waveWidth;
|
|
}
|
|
}
|
|
|
|
void SetupGlowPoint()
|
|
{
|
|
if (glowPoint == null)
|
|
{
|
|
GameObject glowObj = new GameObject("GlowPoint");
|
|
glowObj.transform.SetParent(transform);
|
|
glowPoint = 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));
|
|
glowPoint.sprite = sprite;
|
|
}
|
|
|
|
glowPoint.color = glowColor;
|
|
glowPoint.transform.localScale = Vector3.one * glowSize;
|
|
}
|
|
|
|
void Update()
|
|
{
|
|
if (Application.isPlaying)
|
|
{
|
|
timer += Time.deltaTime;
|
|
if (timer >= updateInterval)
|
|
{
|
|
timer = 0f;
|
|
phaseOffset += updateInterval * speed;
|
|
UpdateWave();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
phaseOffset = Time.realtimeSinceStartup * speed;
|
|
UpdateWave();
|
|
}
|
|
}
|
|
|
|
void UpdateWave()
|
|
{
|
|
Vector3 origin = transform.position;
|
|
Quaternion rotation = transform.rotation;
|
|
|
|
for (int i = 0; i < resolution; i++)
|
|
{
|
|
float x = ((float)i / resolution) * waveWidth;
|
|
float timeOffset = (x / waveWidth) * waveStretch + phaseOffset;
|
|
float waveValue = GetWaveValue(timeOffset % 1.0f);
|
|
|
|
Vector3 localPos = new Vector3(x, waveValue * waveHeight, 0f);
|
|
points[i] = origin + rotation * localPos;
|
|
}
|
|
|
|
if (lineRenderer != null)
|
|
lineRenderer.SetPositions(points);
|
|
|
|
// 更新发光点位置
|
|
if (glowPoint != null)
|
|
{
|
|
Vector3 lastPoint = points[resolution - 1];
|
|
glowPoint.transform.position = lastPoint;
|
|
}
|
|
}
|
|
|
|
public void SetWaveType(WaveType type)
|
|
{
|
|
waveType = type;
|
|
// switch (type)
|
|
// {
|
|
// case WaveType.RobotECG:
|
|
// SetWaveColors(normalColors);
|
|
// break;
|
|
// case WaveType.Noise:
|
|
// SetWaveColors(emergencyColors);
|
|
// break;
|
|
// case WaveType.Abnormal:
|
|
// SetWaveColors(warningColors);
|
|
// break;
|
|
// }
|
|
}
|
|
|
|
private void SetWaveColors(Color[] colors)
|
|
{
|
|
if (lineRenderer != null && colors != null && colors.Length > 0)
|
|
{
|
|
Gradient gradient = new Gradient();
|
|
GradientColorKey[] colorKeys = new GradientColorKey[colors.Length];
|
|
GradientAlphaKey[] alphaKeys = new GradientAlphaKey[2];
|
|
|
|
for (int i = 0; i < colors.Length; i++)
|
|
{
|
|
colorKeys[i] = new GradientColorKey(colors[i], i / (float)(colors.Length - 1));
|
|
}
|
|
|
|
alphaKeys[0] = new GradientAlphaKey(1f, 0f);
|
|
alphaKeys[1] = new GradientAlphaKey(1f, 1f);
|
|
|
|
gradient.SetKeys(colorKeys, alphaKeys);
|
|
lineRenderer.colorGradient = gradient;
|
|
}
|
|
}
|
|
|
|
float GetWaveValue(float time)
|
|
{
|
|
switch (waveType)
|
|
{
|
|
case WaveType.Sine:
|
|
return Mathf.Sin(time * Mathf.PI * 2f);
|
|
|
|
case WaveType.Triangle:
|
|
return 2f * Mathf.Abs(2f * (time - Mathf.Floor(time + 0.5f))) - 1f;
|
|
|
|
case WaveType.Square:
|
|
return Mathf.Sign(Mathf.Sin(time * Mathf.PI * 2f));
|
|
|
|
case WaveType.HumanECG:
|
|
return GenerateHumanECGShape(time);
|
|
|
|
case WaveType.Emergency:
|
|
return GenerateEmergencyShape(time);
|
|
|
|
case WaveType.Noise:
|
|
return GenerateNoiseShape(time);
|
|
|
|
case WaveType.Abnormal:
|
|
return GenerateAbnormalShape(time);
|
|
|
|
case WaveType.Warning:
|
|
return GenerateWarningShape(time);
|
|
|
|
case WaveType.RobotECG:
|
|
default:
|
|
return GenerateRobotECGShape(time);
|
|
}
|
|
}
|
|
|
|
float GenerateRobotECGShape(float time)
|
|
{
|
|
float t = time % 1.0f;
|
|
|
|
float baseValue = 0f;
|
|
|
|
if (t < 0.10f)
|
|
{
|
|
// 上升锯齿:锯齿线性上升
|
|
baseValue = (t / 0.10f) + Mathf.PingPong(t * 80f, 0.1f);
|
|
}
|
|
else if (t < 0.20f)
|
|
{
|
|
// 高电平方波 + 高频扰动
|
|
baseValue = 1f + Mathf.PingPong(t * 120f, 0.1f);
|
|
}
|
|
else if (t < 0.30f)
|
|
{
|
|
// 快速下降:线性下降带锯齿
|
|
baseValue = Mathf.Lerp(1f, -0.8f, (t - 0.20f) / 0.10f) + Mathf.PingPong(t * 100f, 0.05f);
|
|
}
|
|
else if (t < 0.40f)
|
|
{
|
|
// 低电平方波 + 微扰动
|
|
baseValue = -0.8f + Mathf.PingPong(t * 60f, 0.05f);
|
|
}
|
|
else
|
|
{
|
|
// 平缓底噪,锯齿叠加轻扰动
|
|
baseValue = Mathf.Sin(t * 80f) * 0.05f + Mathf.PingPong(t * 10f, 0.02f);
|
|
}
|
|
|
|
return baseValue;
|
|
}
|
|
|
|
float GenerateHumanECGShape(float time)
|
|
{
|
|
float t = time % 1.0f;
|
|
|
|
if (t < 0.1f)
|
|
return Mathf.Lerp(0f, 0.1f, t / 0.1f); // P 波上升
|
|
|
|
else if (t < 0.2f)
|
|
return Mathf.Lerp(0.1f, 0f, (t - 0.1f) / 0.1f); // P 波下降
|
|
|
|
else if (t < 0.22f)
|
|
return Mathf.Lerp(0f, -0.15f, (t - 0.2f) / 0.02f); // Q 波
|
|
|
|
else if (t < 0.26f)
|
|
return Mathf.Lerp(-0.15f, 1f, (t - 0.22f) / 0.04f); // R 波快速上升
|
|
|
|
else if (t < 0.30f)
|
|
return Mathf.Lerp(1f, -0.3f, (t - 0.26f) / 0.04f); // S 波下降
|
|
|
|
else if (t < 0.35f)
|
|
return Mathf.Lerp(-0.3f, 0f, (t - 0.30f) / 0.05f); // 回到0线
|
|
|
|
else if (t < 0.5f)
|
|
return Mathf.Lerp(0f, 0.4f, (t - 0.35f) / 0.15f); // T 波上升
|
|
|
|
else if (t < 0.65f)
|
|
return Mathf.Lerp(0.4f, 0f, (t - 0.5f) / 0.15f); // T 波下降
|
|
|
|
else
|
|
return 0f; // 静息段
|
|
}
|
|
|
|
float GenerateEmergencyShape(float time)
|
|
{
|
|
float t = time % 1.0f;
|
|
float baseValue = 0f;
|
|
|
|
// 使用多个正弦波叠加来创造不规则波形
|
|
float irregularity = Mathf.Sin(t * 20f) * 0.2f +
|
|
Mathf.Sin(t * 35f) * 0.15f +
|
|
Mathf.Sin(t * 50f) * 0.1f;
|
|
|
|
if (t < 0.15f)
|
|
{
|
|
// 快速上升段
|
|
baseValue = Mathf.Lerp(0f, 1.2f, t / 0.15f) + irregularity;
|
|
}
|
|
else if (t < 0.25f)
|
|
{
|
|
// 剧烈波动段
|
|
baseValue = 1.2f + Mathf.Sin(t * 100f) * 0.3f + irregularity;
|
|
}
|
|
else if (t < 0.35f)
|
|
{
|
|
// 快速下降段
|
|
baseValue = Mathf.Lerp(1.2f, -0.8f, (t - 0.25f) / 0.1f) + irregularity;
|
|
}
|
|
else if (t < 0.45f)
|
|
{
|
|
// 不规则波动段
|
|
baseValue = -0.8f + Mathf.Sin(t * 80f) * 0.4f + irregularity;
|
|
}
|
|
else if (t < 0.55f)
|
|
{
|
|
// 快速上升段
|
|
baseValue = Mathf.Lerp(-0.8f, 0.8f, (t - 0.45f) / 0.1f) + irregularity;
|
|
}
|
|
else if (t < 0.65f)
|
|
{
|
|
// 高频震荡段
|
|
baseValue = 0.8f + Mathf.Sin(t * 120f) * 0.2f + irregularity;
|
|
}
|
|
else if (t < 0.75f)
|
|
{
|
|
// 快速下降段
|
|
baseValue = Mathf.Lerp(0.8f, -0.5f, (t - 0.65f) / 0.1f) + irregularity;
|
|
}
|
|
else
|
|
{
|
|
// 不规则底噪段
|
|
baseValue = -0.5f + Mathf.Sin(t * 60f) * 0.3f + irregularity;
|
|
}
|
|
|
|
// 添加随机扰动
|
|
baseValue += Mathf.PerlinNoise(t * 100f, Time.time) * 0.1f;
|
|
|
|
return baseValue;
|
|
}
|
|
|
|
float GenerateNoiseShape(float time)
|
|
{
|
|
float t = time % 1.0f;
|
|
|
|
// 使用纯随机值生成噪音
|
|
float noise = Random.Range(-noiseAmplitude, noiseAmplitude);
|
|
|
|
// 确保波形在合理范围内
|
|
return Mathf.Clamp(noise, -1f, 1f);
|
|
}
|
|
|
|
float GenerateAbnormalShape(float time)
|
|
{
|
|
float t = time % 1.0f;
|
|
float baseValue = GenerateRobotECGShape(t);
|
|
|
|
// 添加随机抖动
|
|
if (Random.value < 0.1f) // 10%的概率发生抖动
|
|
{
|
|
float jitterAmount = Random.Range(-0.3f, 0.3f);
|
|
baseValue += jitterAmount;
|
|
}
|
|
|
|
// 添加周期性波动
|
|
float periodicWave = Mathf.Sin(t * 20f) * 0.1f;
|
|
baseValue += periodicWave;
|
|
|
|
return Mathf.Clamp(baseValue, -1f, 1f);
|
|
}
|
|
|
|
float GenerateWarningShape(float time)
|
|
{
|
|
float t = time % 1.0f;
|
|
float baseValue = 0f;
|
|
|
|
// 警告状态的特征波形
|
|
if (t < 0.15f)
|
|
{
|
|
// 快速上升段,带有轻微抖动
|
|
baseValue = Mathf.Lerp(0f, 1.2f, t / 0.15f) + Mathf.Sin(t * 100f) * 0.1f;
|
|
}
|
|
else if (t < 0.25f)
|
|
{
|
|
// 高频震荡段
|
|
baseValue = 1.2f + Mathf.Sin(t * 200f) * 0.2f;
|
|
}
|
|
else if (t < 0.35f)
|
|
{
|
|
// 快速下降段,带有不规则波动
|
|
baseValue = Mathf.Lerp(1.2f, -0.5f, (t - 0.25f) / 0.1f) + Mathf.Sin(t * 150f) * 0.15f;
|
|
}
|
|
else if (t < 0.45f)
|
|
{
|
|
// 不规则波动段
|
|
baseValue = -0.5f + Mathf.Sin(t * 80f) * 0.3f + Mathf.Sin(t * 120f) * 0.2f;
|
|
}
|
|
else if (t < 0.55f)
|
|
{
|
|
// 快速上升段,带有高频抖动
|
|
baseValue = Mathf.Lerp(-0.5f, 0.8f, (t - 0.45f) / 0.1f) + Mathf.Sin(t * 180f) * 0.15f;
|
|
}
|
|
else if (t < 0.65f)
|
|
{
|
|
// 剧烈波动段
|
|
baseValue = 0.8f + Mathf.Sin(t * 250f) * 0.25f + Mathf.Sin(t * 150f) * 0.15f;
|
|
}
|
|
else if (t < 0.75f)
|
|
{
|
|
// 快速下降段,带有不规则波动
|
|
baseValue = Mathf.Lerp(0.8f, -0.3f, (t - 0.65f) / 0.1f) + Mathf.Sin(t * 200f) * 0.2f;
|
|
}
|
|
else
|
|
{
|
|
// 不规则底噪段,增加波动频率
|
|
baseValue = -0.3f + Mathf.Sin(t * 100f) * 0.2f + Mathf.Sin(t * 150f) * 0.15f;
|
|
}
|
|
|
|
// 添加随机扰动,增加不稳定性
|
|
if (Random.value < 0.2f) // 20%的概率发生较大抖动
|
|
{
|
|
float jitterAmount = Random.Range(-0.3f, 0.3f);
|
|
baseValue += jitterAmount;
|
|
}
|
|
|
|
// 添加随机尖峰,增加警告感
|
|
if (Random.value < 0.1f) // 10%的概率出现尖峰
|
|
{
|
|
float spikeAmount = Random.Range(0.2f, 0.4f);
|
|
baseValue += spikeAmount;
|
|
}
|
|
|
|
// 确保波形在合理范围内
|
|
return Mathf.Clamp(baseValue, -1f, 1f);
|
|
}
|
|
}
|