using UnityEngine; using System.Collections.Generic; namespace AibisDream.MiniGame.Language { /// /// 候选粒子(可交互的主要粒子) /// public class CandidateParticle : TextParticle { [Header("粒子状态(目标/非目标,颜色由 Manager 配置,可与红蓝解绑)")] public bool isRed = false; // 当前是否为目标粒子(用于颜色/样式,可配成蓝) public bool isOrange = false; // 是否受到效果影响(橙色) public bool originalIsRed = false; // 原始是否为目标粒子(不变,用于字符逻辑) public bool hasEffect = false; // 是否有效果 public bool isTemporaryRed = false; // 临时红色状态 [Header("连接")] public List connections = new List(); [Header("效果")] public float changeSpeedMultiplier = 1f; public Vector2 vibrationOffset; public float vibrationPhase; public float effectTimer; public float effectAlpha; public float effectScale = 1f; public float effectGlow; [Header("焦虑效果")] public float anxietyShakePhase; public float anxietyShakeIntensity; public float anxietyFloatPhase; public float anxietyFloatSpeed; public Vector2 anxietyShakeOffset; public float anxietyFloatY; [Header("非目标干扰效果")] public float interferenceShakeIntensity = 0f; public float interferenceShakeSpeed = 8f; public float interferenceFloatAmplitude = 0.015f; private float interferenceShakePhase; private float interferenceFloatPhase; private Vector2 interferenceShakeOffset; private float interferenceFloatY; [Header("波形关联")] public float calmProgress = 0f; // 平静进度(0-1) public float dissolveProgress = 0f; // 消散进度(0-1) public WaveformPoint waveformPoint; // 关联的波形点 // 颜色配置(由Manager设置) private Color targetColor = new Color(1f, 0.39f, 0.39f, 1f); // 目标粒子颜色 private Color nonTargetColor = new Color(0.2f, 0.78f, 1f, 1f); // 非目标粒子颜色 private Color propagationColor = new Color(1f, 0.59f, 0.2f, 1f); // 传播颜色 private Color calmColor = new Color(0.78f, 0.59f, 0.59f, 1f); // 平静后颜色 // 字体样式配置(由Manager设置) private float targetFontSize = 3.5f; private float nonTargetFontSize = 2.5f; private bool targetBold = true; private bool nonTargetBold = false; protected override void Awake() { base.Awake(); baseAlpha = 0.6f; // 0-1 范围的透明度 probability = Random.Range(0.1f, 1f); alpha = baseAlpha + probability * 0.4f; // 最大 1.0 size = nonTargetFontSize; // 默认使用非目标粒子大小 velocity = new Vector2(Random.Range(-0.5f, 0.5f), Random.Range(-0.5f, 0.5f)); changeInterval = Random.Range(1f, 2.5f); interferenceShakePhase = Random.Range(0f, Mathf.PI * 2f); interferenceFloatPhase = Random.Range(0f, Mathf.PI * 2f); if (textMesh != null) { textMesh.fontSize = size; UpdateFontStyle(); } } protected override void Update() { base.Update(); // 更新效果动画 if (hasEffect) { UpdateEffectAnimation(); } // 更新焦虑效果 if (isRed && (anxietyShakeIntensity > 0)) { UpdateAnxietyEffect(); } // 非目标粒子干扰抖动 if (!isRed && !isCalmed && interferenceShakeIntensity > 0) { UpdateInterferenceEffect(); } } private void UpdateEffectAnimation() { if (effectTimer > 0) { effectTimer -= Time.deltaTime; // 振动效果 vibrationPhase += Time.deltaTime * 15f; float vibrationIntensity = 0.02f; vibrationOffset = new Vector2( Mathf.Cos(vibrationPhase) * vibrationIntensity, Mathf.Sin(vibrationPhase * 1.3f) * vibrationIntensity ); // 透明度动画(0-1 范围) effectAlpha = Mathf.Lerp(0.6f, 1f, (Mathf.Sin(Time.time * 3f) + 1f) / 2f); // 缩放动画 effectScale = Mathf.Lerp(0.95f, 1.05f, (Mathf.Sin(Time.time * 4.5f) + 1f) / 2f); // 发光强度 effectGlow = Mathf.Lerp(0.06f, 0.1f, (effectAlpha - 0.6f) / 0.4f); } } private void UpdateAnxietyEffect() { // 根据平静进度减少抖动强度 float shakeIntensity = anxietyShakeIntensity * (1 - calmProgress) * 0.01f; float floatAmplitude = 0.03f * (1 - calmProgress); if (calmProgress < 0.9f) { anxietyShakePhase += Time.deltaTime * 10f; anxietyFloatPhase += anxietyFloatSpeed; } // 计算抖动偏移 anxietyShakeOffset = new Vector2( Mathf.Cos(anxietyShakePhase) * shakeIntensity + Mathf.Sin(anxietyShakePhase * 1.7f) * shakeIntensity * 0.5f, Mathf.Sin(anxietyShakePhase * 1.3f) * shakeIntensity + Mathf.Cos(anxietyShakePhase * 0.9f) * shakeIntensity * 0.5f ); // 计算漂浮偏移 anxietyFloatY = Mathf.Sin(anxietyFloatPhase) * floatAmplitude; } protected override void UpdateVisuals() { if (textMesh == null) return; // 更新字体样式(大小和加粗) UpdateFontStyle(); // 计算显示位置(叠加干扰抖动) Vector3 displayOffset = (Vector3)(vibrationOffset + anxietyShakeOffset + interferenceShakeOffset) + Vector3.up * (anxietyFloatY + interferenceFloatY); textMesh.transform.localPosition = displayOffset; // 计算颜色和透明度 Color color = Color.white; float displayAlpha = alpha; if (hasEffect && effectTimer > 0) { displayAlpha = effectAlpha; textMesh.transform.localScale = Vector3.one * effectScale; } // 根据消散进度减少透明度 displayAlpha *= (1 - dissolveProgress); if (isRed) { // 目标粒子:根据平静进度从目标颜色过渡到平静颜色 float r = Mathf.Lerp(targetColor.r, calmColor.r, calmProgress); float g = Mathf.Lerp(targetColor.g, calmColor.g, calmProgress); float b = Mathf.Lerp(targetColor.b, calmColor.b, calmProgress); color = new Color(r, g, b, displayAlpha); } else if (isOrange) { // 传播效果颜色 color = new Color(propagationColor.r, propagationColor.g, propagationColor.b, displayAlpha); } else { // 非目标粒子颜色 color = new Color(nonTargetColor.r, nonTargetColor.g, nonTargetColor.b, displayAlpha); } textMesh.color = color; // 更新光晕 if (glowSprite != null) { glowSprite.color = new Color(color.r, color.g, color.b, color.a * 0.5f); float glowScale = probability * 0.5f; if (hasEffect) glowScale += effectGlow; glowSprite.transform.localScale = Vector3.one * glowScale; } } /// /// 目标粒子:chineseChars 随机单字;非目标粒子:从笑话/干扰短句字符中随机。 /// 使用 IsTarget 判断,与红蓝颜色解绑。 /// protected override string GetNextDisplayChar() { return IsTarget ? GetRandomChar() : GetRandomCharFromPhrases(); } /// /// 是否为目标粒子(由 originalIsRed 表示,与显示颜色解绑) /// private bool IsTarget => originalIsRed; private void UpdateInterferenceEffect() { interferenceShakePhase += Time.deltaTime * interferenceShakeSpeed; interferenceFloatPhase += Time.deltaTime * interferenceShakeSpeed * 0.3f; float intensity = interferenceShakeIntensity; interferenceShakeOffset = new Vector2( Mathf.Sin(interferenceShakePhase) * intensity + Mathf.Sin(interferenceShakePhase * 2.3f) * intensity * 0.4f, Mathf.Cos(interferenceShakePhase * 1.7f) * intensity * 0.7f + Mathf.Sin(interferenceShakePhase * 0.6f) * intensity * 0.3f ); interferenceFloatY = Mathf.Sin(interferenceFloatPhase) * interferenceFloatAmplitude; } public void SetInterferenceParams(float shakeIntensity, float shakeSpeed, float changeIntv, float floatAmplitude) { interferenceShakeIntensity = shakeIntensity; interferenceShakeSpeed = shakeSpeed; interferenceFloatAmplitude = floatAmplitude; if (!isRed) { changeInterval = Mathf.Max(0.05f, changeIntv * Random.Range(0.7f, 1.3f)); } } public void InitializeAnxietyEffect() { anxietyShakePhase = Random.Range(0f, Mathf.PI * 2f); anxietyShakeIntensity = Random.Range(2f, 4f); anxietyFloatPhase = Random.Range(0f, Mathf.PI * 2f); anxietyFloatSpeed = Random.Range(0.02f, 0.04f); } public void ApplyEffect(float duration = 1f) { hasEffect = true; effectTimer = duration; isOrange = true; isRed = false; changeSpeedMultiplier = 3f; vibrationPhase = Random.Range(0f, Mathf.PI * 2f); } public void RemoveEffect() { hasEffect = false; isOrange = false; isRed = false; changeSpeedMultiplier = 1f; vibrationOffset = Vector2.zero; effectTimer = 0; } /// /// 设置粒子颜色配置 /// public void SetColors(Color target, Color nonTarget, Color propagation, Color calm) { targetColor = target; nonTargetColor = nonTarget; propagationColor = propagation; calmColor = calm; } /// /// 设置字体样式配置 /// public void SetFontStyles(float targetSize, float nonTargetSize, bool targetIsBold, bool nonTargetIsBold) { targetFontSize = targetSize; nonTargetFontSize = nonTargetSize; targetBold = targetIsBold; nonTargetBold = nonTargetIsBold; // 立即应用 if (textMesh != null) { UpdateFontStyle(); } } /// /// 更新字体样式(根据粒子状态) /// private void UpdateFontStyle() { if (textMesh == null) return; // 根据是否为目标粒子设置大小和加粗 if (isRed) { textMesh.fontSize = targetFontSize; textMesh.fontStyle = targetBold ? TMPro.FontStyles.Bold : TMPro.FontStyles.Normal; } else { textMesh.fontSize = nonTargetFontSize; textMesh.fontStyle = nonTargetBold ? TMPro.FontStyles.Bold : TMPro.FontStyles.Normal; } } } }