using UnityEngine; using TMPro; using DG.Tweening; using System.Collections.Generic; namespace AibisDream.MiniGame.Language { /// /// 文字粒子基类 /// public class TextParticle : MonoBehaviour { [Header("组件")] public TextMeshPro textMesh; public SpriteRenderer glowSprite; [Header("属性")] public Vector2 velocity; public float alpha; public float baseAlpha = 1f; public float size = 3f; public float probability = 1f; public string currentChar; [Header("状态")] public bool isStatic = false; public bool isCalmed = false; protected float changeTimer; protected float changeInterval = 1f; protected Bounds movementBounds; protected TMP_FontAsset customFont; // 字符集 protected static string chineseChars = "的一是在不了有和人这中大为上个国我以要他时来用们生到作地于出就分对成会可主发年动同工也能下过子说产种面而方后多定行学法所民得经十三之进着等部度家电力里如水化高自二理起小物现实加量都两体制机当使点从业本去把性好应开它合还因由其些然前外天政四日那社义事平形相全表间样与关各重新线内数正心反你明看原又么利比或但质气第向道命此变条只没结解问意建月公无系军很情者最立代想已通并提直题党程展五果料象员革位入常文总次品式活设及管特件长求老头基资边流路级少图山统接知较将组见计别她手角期根论运农指几九区强放决西被干做必战先回则任取据处队南给色光门即保治北造百规热领七海口东导器压志世金增争济阶油思术极交受联什认六共权收证改清己美再采转更单风切打白教速花带安场身车例真务具万每目至达走积示议声报斗完类八离华名确才科张信马节话米整空元况今集温传土许步群广石记需段研界拉林律叫且究观越织装影算低持音众书布复容儿须际商非验连断深难近矿千周委素技备半办青省列习响约支般史感劳便团往酸历市克何除消构府称太准精值号率族维划选标写存候毛亲快效斯院查江型眼王按格养易置派层片始却专状育厂京识适属圆包火住调满县局照参红细引听该铁价严龙飞"; protected static string[] chineseWords = { "不安", "紧张", "焦虑", "担忧", "烦躁", "恐慌", "恐惧", "绝望", "痛苦", "悲伤", "愤怒", "孤独", "无助", "迷茫", "困惑", "压抑", "沉重", "疲惫", "空虚", "失落" }; protected virtual void Awake() { if (textMesh == null) textMesh = GetComponentInChildren(); if (textMesh == null) { var textObj = new GameObject("Text"); textObj.transform.SetParent(transform, false); // 添加 RectTransform(在 Canvas 下必需) RectTransform rectTransform = textObj.AddComponent(); rectTransform.localPosition = Vector3.zero; rectTransform.localScale = Vector3.one; rectTransform.sizeDelta = new Vector2(10, 10); // 设置足够大的尺寸 rectTransform.anchorMin = new Vector2(0.5f, 0.5f); rectTransform.anchorMax = new Vector2(0.5f, 0.5f); rectTransform.pivot = new Vector2(0.5f, 0.5f); // 添加 TextMeshPro 组件 textMesh = textObj.AddComponent(); textMesh.alignment = TextAlignmentOptions.Center; textMesh.fontSize = size; textMesh.enableAutoSizing = false; textMesh.overflowMode = TextOverflowModes.Overflow; // 允许溢出,不裁剪 // 设置字体(优先使用自定义字体) SetupFont(); // 设置渲染层级,确保文字显示在正确的层 textMesh.sortingOrder = 10; } else { // 如果已存在 textMesh,也要确保设置字体 SetupFont(); } // 创建光晕 if (glowSprite == null) { var glowObj = new GameObject("Glow"); glowObj.transform.SetParent(transform); glowObj.transform.localPosition = Vector3.zero; glowObj.transform.localScale = Vector3.one * 0.5f; glowSprite = glowObj.AddComponent(); glowSprite.sprite = CreateCircleSprite(); glowSprite.color = new Color(1, 1, 1, 0.2f); } changeTimer = Random.Range(0.5f, 1.5f); currentChar = GetRandomChar(); UpdateText(); } protected virtual void Update() { if (!isStatic && !isCalmed) { // 更新位置 transform.position += (Vector3)velocity * Time.deltaTime; // 边界检测 CheckBounds(); // 字符变化 changeTimer -= Time.deltaTime; if (changeTimer <= 0) { currentChar = GetRandomChar(); UpdateText(); changeTimer = changeInterval; } // 速度衰减 velocity *= 0.95f; } // 更新视觉效果 UpdateVisuals(); } public void SetMovementBounds(Bounds bounds) { movementBounds = bounds; } protected void CheckBounds() { Vector3 pos = transform.position; bool bounced = false; if (pos.x < movementBounds.min.x || pos.x > movementBounds.max.x) { velocity.x *= -1; pos.x = Mathf.Clamp(pos.x, movementBounds.min.x, movementBounds.max.x); bounced = true; } if (pos.y < movementBounds.min.y || pos.y > movementBounds.max.y) { velocity.y *= -1; pos.y = Mathf.Clamp(pos.y, movementBounds.min.y, movementBounds.max.y); bounced = true; } if (bounced) transform.position = pos; } protected string GetRandomChar() { return chineseChars[Random.Range(0, chineseChars.Length)].ToString(); } protected string GetRandomWord() { return chineseWords[Random.Range(0, chineseWords.Length)]; } protected void UpdateText() { if (textMesh != null) textMesh.text = currentChar; } protected virtual void UpdateVisuals() { if (textMesh != null) { Color color = textMesh.color; color.a = alpha; // alpha 已经是 0-1 范围 textMesh.color = color; } } public void ApplyForce(Vector2 force) { velocity += force; } /// /// 设置字体资源 /// public void SetFont(TMP_FontAsset fontAsset) { customFont = fontAsset; SetupFont(); } /// /// 内部方法:设置字体 /// private void SetupFont() { if (textMesh == null) return; // 优先级:自定义字体 > 默认字体 > 警告 if (customFont != null) { textMesh.font = customFont; } else if (TMP_Settings.defaultFontAsset != null) { textMesh.font = TMP_Settings.defaultFontAsset; } else { Debug.LogWarning("[TextParticle] TextMeshPro 字体未设置!请在 LanguageParticleManager 中指定中文字体资源,或在 Project Settings > TextMesh Pro > Settings 中设置默认字体。"); } } // 创建简单的圆形Sprite用于光晕 private Sprite CreateCircleSprite() { int resolution = 32; Texture2D texture = new Texture2D(resolution, resolution); Color[] pixels = new Color[resolution * resolution]; Vector2 center = new Vector2(resolution / 2f, resolution / 2f); float radius = resolution / 2f; for (int y = 0; y < resolution; y++) { for (int x = 0; x < resolution; x++) { float dist = Vector2.Distance(new Vector2(x, y), center); float alpha = 1f - Mathf.Clamp01(dist / radius); alpha = Mathf.Pow(alpha, 2); // 平滑衰减 pixels[y * resolution + x] = new Color(1, 1, 1, alpha); } } texture.SetPixels(pixels); texture.Apply(); return Sprite.Create(texture, new Rect(0, 0, resolution, resolution), new Vector2(0.5f, 0.5f)); } } }