using UnityEngine; [ExecuteInEditMode] [RequireComponent(typeof(LineRenderer))] public class RobotECGWave : MonoBehaviour { public enum WaveType { RobotECG, Sine, Triangle, Square, HumanECG, Emergency, Noise, Abnormal, Warning, Flatline } [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.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(); // 创建一个简单的圆形精灵 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.Flatline: return 0f; // 返回0表示一条直线 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); } }