Unity TMP_Text 竖排实现指南:从基础到进阶的完整方案

Unity TMP_Text 竖排实现指南:从基础到进阶的完整方案

在Unity游戏开发中,TextMeshPro(TMP)作为新一代文本渲染组件,提供了比传统UI Text更强大的功能和视觉效果。当需要实现竖排文字时(如中文古籍、日式游戏UI等场景),TMP_Text的灵活配置能够满足多样化需求。本文将系统讲解三种主流实现方案,包含详细参数配置和代码示例。

一、TMP_Text竖排基础原理

TMP_Text的竖排实现主要基于两个核心机制:字符排列方向控制和文本对齐方式。与横排文本不同,竖排需要重新定义字符的基线方向和行进方向。TMP通过TextGenerationSettings中的horizontalAlignmentverticalAlignment参数,结合自定义着色器或脚本控制,实现文字的垂直排列。

1.1 字符方向控制参数

参数 功能 适用场景
HorizontalOverflow 水平溢出处理 控制单行文字宽度限制
VerticalOverflow 垂直溢出处理 控制多行文字高度限制
Alignment 文本对齐方式 决定文字在矩形框内的位置
CharacterSpacing 字符间距 调整竖排时字符垂直间距

二、方案一:通过Inspector面板配置竖排

2.1 基础配置步骤

  1. 创建TMP对象:在Hierarchy中右键选择UI > Text - TextMeshPro
  2. 修改对齐参数
    • 在Inspector的Text Input区域,设置AlignmentMiddle Center
    • 展开Extra Settings,设置Vertical AlignmentMiddle
  3. 调整布局组件
    • 添加Content Size Fitter组件,设置Horizontal FitPreferred Size
    • 添加Vertical Layout Group(需先转换为RectTransform)

2.2 关键参数详解

  • Font Size:建议使用20-30pt范围,过大可能导致字符重叠
  • Line Spacing:竖排时实际控制行间距,建议设置为1.2-1.5倍字高
  • Word Wrapping:必须启用,否则长文本会超出边界
  • Auto Size:建议开启Enable Auto Sizing,设置最小/最大字号

2.3 示例配置

  1. // 在Start方法中初始化竖排参数
  2. void InitializeVerticalText() {
  3. TMP_Text textComponent = GetComponent<TMP_Text>();
  4. textComponent.alignment = TextAlignmentOptions.Center;
  5. textComponent.enableAutoSizing = true;
  6. textComponent.fontSizeMin = 20;
  7. textComponent.fontSizeMax = 30;
  8. textComponent.lineSpacing = 1.3f; // 关键竖排行距参数
  9. }

三、方案二:使用自定义着色器实现精确控制

3.1 着色器开发原理

TMP_Text的着色器系统允许通过修改顶点着色器来改变字符排列方向。核心思路是将字符的UV坐标旋转90度,并调整顶点位置。

3.2 完整着色器代码

  1. Shader "TextMeshPro/Vertical Text" {
  2. Properties {
  3. _MainTex ("Font Atlas", 2D) = "white" {}
  4. _FaceColor ("Text Color", Color) = (1,1,1,1)
  5. _OutlineColor ("Outline Color", Color) = (0,0,0,1)
  6. _OutlineWidth ("Outline Width", Range(0, 0.1)) = 0.01
  7. _VertexOffsetX ("Vertex Offset X", Float) = 0
  8. _VertexOffsetY ("Vertex Offset Y", Float) = 0
  9. }
  10. SubShader {
  11. Tags { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" }
  12. Lighting Off Cull Off ZWrite Off Blend One OneMinusSrcAlpha
  13. Pass {
  14. CGPROGRAM
  15. #pragma vertex VertShader
  16. #pragma fragment PixShader
  17. #include "UnityCG.cginc"
  18. #include "UnityUI.cginc"
  19. struct appdata_t {
  20. float4 vertex : POSITION;
  21. float4 color : COLOR;
  22. float2 texcoord : TEXCOORD0;
  23. };
  24. struct v2f {
  25. float4 vertex : SV_POSITION;
  26. fixed4 color : COLOR;
  27. float2 texcoord : TEXCOORD0;
  28. float4 worldPosition : TEXCOORD1;
  29. };
  30. sampler2D _MainTex;
  31. fixed4 _FaceColor;
  32. float _VertexOffsetX;
  33. float _VertexOffsetY;
  34. v2f VertShader(appdata_t v) {
  35. v2f o;
  36. // 关键修改:旋转字符方向
  37. float2 rotatedUV = float2(-v.texcoord.y, v.texcoord.x);
  38. o.worldPosition = v.vertex;
  39. o.vertex = UnityObjectToClipPos(v.vertex);
  40. o.texcoord = rotatedUV;
  41. o.color = v.color * _FaceColor;
  42. return o;
  43. }
  44. fixed4 PixShader(v2f i) : SV_Target {
  45. fixed4 col = tex2D(_MainTex, i.texcoord) * i.color;
  46. clip(col.a - 0.01);
  47. return col;
  48. }
  49. ENDCG
  50. }
  51. }
  52. }

3.3 着色器应用步骤

  1. 创建新材质并应用上述着色器
  2. 在TMP_Text组件的Material属性中指定该材质
  3. 调整Character SpacingLine Spacing参数优化显示效果

四、方案三:脚本动态控制竖排

4.1 核心实现思路

通过脚本修改每个字符的顶点位置,实现动态竖排效果。适用于需要运行时改变排列方向的场景。

4.2 完整代码实现

  1. using UnityEngine;
  2. using TMPro;
  3. [RequireComponent(typeof(TMP_Text))]
  4. public class VerticalTextController : MonoBehaviour {
  5. [SerializeField] private float characterSpacing = 30f;
  6. [SerializeField] private float lineSpacing = 10f;
  7. private TMP_Text textComponent;
  8. private TMP_TextInfo textInfo;
  9. void Start() {
  10. textComponent = GetComponent<TMP_Text>();
  11. textInfo = textComponent.textInfo;
  12. UpdateVerticalText();
  13. }
  14. void UpdateVerticalText() {
  15. if (textInfo.characterCount == 0) return;
  16. // 重置所有字符位置
  17. for (int i = 0; i < textInfo.characterCount; i++) {
  18. TMP_CharacterInfo charInfo = textInfo.characterInfo[i];
  19. if (!charInfo.isVisible) continue;
  20. // 获取原始顶点数据
  21. Vector3[] vertices = charInfo.vertices;
  22. Vector2 size = charInfo.topRight - charInfo.bottomLeft;
  23. // 计算新位置(竖排排列)
  24. float baseY = charInfo.bottomLeft.y;
  25. float offsetX = i * characterSpacing;
  26. float offsetY = -i * (size.y + lineSpacing);
  27. // 修改顶点位置
  28. vertices[0].x = offsetX; vertices[0].y = baseY + offsetY;
  29. vertices[1].x = offsetX; vertices[1].y = baseY + size.y + offsetY;
  30. vertices[2].x = offsetX + size.x; vertices[2].y = baseY + size.y + offsetY;
  31. vertices[3].x = offsetX + size.x; vertices[3].y = baseY + offsetY;
  32. // 更新网格(需要TMP_MeshInfo访问)
  33. // 实际项目中需通过textComponent.meshInfo数组更新
  34. }
  35. // 强制刷新(简化示例,实际需更精确的mesh更新)
  36. textComponent.ForceMeshUpdate();
  37. }
  38. // 实际项目中更完整的实现应处理:
  39. // 1. 多行文本的换行逻辑
  40. // 2. 动态文本变化的监听
  41. // 3. 性能优化(对象池等)
  42. }

五、常见问题解决方案

5.1 字符重叠问题

原因:字符间距设置不当或字体选择不合适
解决方案

  • 增加Character Spacing值(建议20-40)
  • 选择等宽字体(如Noto Sans CJK SC)
  • 调整Line Spacing为1.2-1.5倍字高

5.2 动态文本更新失效

原因:未正确处理TMP的文本更新机制
解决方案

  1. // 正确监听文本变化的方式
  2. void OnEnable() {
  3. textComponent.onTextChanged.AddListener(OnTextChanged);
  4. }
  5. void OnDisable() {
  6. textComponent.onTextChanged.RemoveListener(OnTextChanged);
  7. }
  8. void OnTextChanged(string obj) {
  9. UpdateVerticalText();
  10. }

5.3 性能优化建议

  1. 批处理优化:将静态竖排文本合并为单个TMP对象
  2. 材质实例化:避免为每个竖排文本创建新材质
  3. 动态文本缓存:对频繁更新的文本使用对象池

六、进阶应用场景

6.1 混合横竖排文本

  1. // 示例:同一TMP对象中部分横排部分竖排
  2. public void SetMixedText(string horizontalText, string verticalText) {
  3. textComponent.text = $"<align=center>{horizontalText}\n</align>";
  4. // 实际实现需要更复杂的富文本处理或多个TMP对象组合
  5. }

6.2 曲线竖排效果

通过修改顶点着色器中的position计算,可以实现沿路径排列的竖排文本:

  1. // 在顶点着色器中添加路径计算
  2. float2 pathPosition = CalculatePathPosition(i.worldPosition.x);
  3. o.vertex.xy += pathPosition * _CurveStrength;

七、最佳实践总结

  1. 字体选择:优先使用支持CJK的字体(如思源黑体、Noto系列)
  2. 参数基准
    • 字号:24-32pt(移动端)
    • 字符间距:30-50单位
    • 行间距:1.3-1.8倍字高
  3. 性能基准
    • 单个场景竖排TMP对象不超过50个
    • 动态文本更新频率控制在30fps以下

通过以上三种方案的灵活组合,开发者可以应对从简单静态文本到复杂动态效果的各类竖排需求。实际项目中建议从Inspector配置方案开始,遇到特殊需求时再考虑着色器或脚本方案。