Unity TMP_Text 竖排实现指南:从基础到进阶的完整方案
Unity TMP_Text 竖排实现指南:从基础到进阶的完整方案
在Unity游戏开发中,TextMeshPro(TMP)作为新一代文本渲染组件,提供了比传统UI Text更强大的功能和视觉效果。当需要实现竖排文字时(如中文古籍、日式游戏UI等场景),TMP_Text的灵活配置能够满足多样化需求。本文将系统讲解三种主流实现方案,包含详细参数配置和代码示例。
一、TMP_Text竖排基础原理
TMP_Text的竖排实现主要基于两个核心机制:字符排列方向控制和文本对齐方式。与横排文本不同,竖排需要重新定义字符的基线方向和行进方向。TMP通过TextGenerationSettings
中的horizontalAlignment
和verticalAlignment
参数,结合自定义着色器或脚本控制,实现文字的垂直排列。
1.1 字符方向控制参数
参数 | 功能 | 适用场景 |
---|---|---|
HorizontalOverflow |
水平溢出处理 | 控制单行文字宽度限制 |
VerticalOverflow |
垂直溢出处理 | 控制多行文字高度限制 |
Alignment |
文本对齐方式 | 决定文字在矩形框内的位置 |
CharacterSpacing |
字符间距 | 调整竖排时字符垂直间距 |
二、方案一:通过Inspector面板配置竖排
2.1 基础配置步骤
- 创建TMP对象:在Hierarchy中右键选择
UI > Text - TextMeshPro
- 修改对齐参数:
- 在Inspector的
Text Input
区域,设置Alignment
为Middle Center
- 展开
Extra Settings
,设置Vertical Alignment
为Middle
- 在Inspector的
- 调整布局组件:
- 添加
Content Size Fitter
组件,设置Horizontal Fit
为Preferred 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 示例配置
// 在Start方法中初始化竖排参数
void InitializeVerticalText() {
TMP_Text textComponent = GetComponent<TMP_Text>();
textComponent.alignment = TextAlignmentOptions.Center;
textComponent.enableAutoSizing = true;
textComponent.fontSizeMin = 20;
textComponent.fontSizeMax = 30;
textComponent.lineSpacing = 1.3f; // 关键竖排行距参数
}
三、方案二:使用自定义着色器实现精确控制
3.1 着色器开发原理
TMP_Text的着色器系统允许通过修改顶点着色器来改变字符排列方向。核心思路是将字符的UV坐标旋转90度,并调整顶点位置。
3.2 完整着色器代码
Shader "TextMeshPro/Vertical Text" {
Properties {
_MainTex ("Font Atlas", 2D) = "white" {}
_FaceColor ("Text Color", Color) = (1,1,1,1)
_OutlineColor ("Outline Color", Color) = (0,0,0,1)
_OutlineWidth ("Outline Width", Range(0, 0.1)) = 0.01
_VertexOffsetX ("Vertex Offset X", Float) = 0
_VertexOffsetY ("Vertex Offset Y", Float) = 0
}
SubShader {
Tags { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" }
Lighting Off Cull Off ZWrite Off Blend One OneMinusSrcAlpha
Pass {
CGPROGRAM
#pragma vertex VertShader
#pragma fragment PixShader
#include "UnityCG.cginc"
#include "UnityUI.cginc"
struct appdata_t {
float4 vertex : POSITION;
float4 color : COLOR;
float2 texcoord : TEXCOORD0;
};
struct v2f {
float4 vertex : SV_POSITION;
fixed4 color : COLOR;
float2 texcoord : TEXCOORD0;
float4 worldPosition : TEXCOORD1;
};
sampler2D _MainTex;
fixed4 _FaceColor;
float _VertexOffsetX;
float _VertexOffsetY;
v2f VertShader(appdata_t v) {
v2f o;
// 关键修改:旋转字符方向
float2 rotatedUV = float2(-v.texcoord.y, v.texcoord.x);
o.worldPosition = v.vertex;
o.vertex = UnityObjectToClipPos(v.vertex);
o.texcoord = rotatedUV;
o.color = v.color * _FaceColor;
return o;
}
fixed4 PixShader(v2f i) : SV_Target {
fixed4 col = tex2D(_MainTex, i.texcoord) * i.color;
clip(col.a - 0.01);
return col;
}
ENDCG
}
}
}
3.3 着色器应用步骤
- 创建新材质并应用上述着色器
- 在TMP_Text组件的
Material
属性中指定该材质 - 调整
Character Spacing
和Line Spacing
参数优化显示效果
四、方案三:脚本动态控制竖排
4.1 核心实现思路
通过脚本修改每个字符的顶点位置,实现动态竖排效果。适用于需要运行时改变排列方向的场景。
4.2 完整代码实现
using UnityEngine;
using TMPro;
[RequireComponent(typeof(TMP_Text))]
public class VerticalTextController : MonoBehaviour {
[SerializeField] private float characterSpacing = 30f;
[SerializeField] private float lineSpacing = 10f;
private TMP_Text textComponent;
private TMP_TextInfo textInfo;
void Start() {
textComponent = GetComponent<TMP_Text>();
textInfo = textComponent.textInfo;
UpdateVerticalText();
}
void UpdateVerticalText() {
if (textInfo.characterCount == 0) return;
// 重置所有字符位置
for (int i = 0; i < textInfo.characterCount; i++) {
TMP_CharacterInfo charInfo = textInfo.characterInfo[i];
if (!charInfo.isVisible) continue;
// 获取原始顶点数据
Vector3[] vertices = charInfo.vertices;
Vector2 size = charInfo.topRight - charInfo.bottomLeft;
// 计算新位置(竖排排列)
float baseY = charInfo.bottomLeft.y;
float offsetX = i * characterSpacing;
float offsetY = -i * (size.y + lineSpacing);
// 修改顶点位置
vertices[0].x = offsetX; vertices[0].y = baseY + offsetY;
vertices[1].x = offsetX; vertices[1].y = baseY + size.y + offsetY;
vertices[2].x = offsetX + size.x; vertices[2].y = baseY + size.y + offsetY;
vertices[3].x = offsetX + size.x; vertices[3].y = baseY + offsetY;
// 更新网格(需要TMP_MeshInfo访问)
// 实际项目中需通过textComponent.meshInfo数组更新
}
// 强制刷新(简化示例,实际需更精确的mesh更新)
textComponent.ForceMeshUpdate();
}
// 实际项目中更完整的实现应处理:
// 1. 多行文本的换行逻辑
// 2. 动态文本变化的监听
// 3. 性能优化(对象池等)
}
五、常见问题解决方案
5.1 字符重叠问题
原因:字符间距设置不当或字体选择不合适
解决方案:
- 增加
Character Spacing
值(建议20-40) - 选择等宽字体(如Noto Sans CJK SC)
- 调整
Line Spacing
为1.2-1.5倍字高
5.2 动态文本更新失效
原因:未正确处理TMP的文本更新机制
解决方案:
// 正确监听文本变化的方式
void OnEnable() {
textComponent.onTextChanged.AddListener(OnTextChanged);
}
void OnDisable() {
textComponent.onTextChanged.RemoveListener(OnTextChanged);
}
void OnTextChanged(string obj) {
UpdateVerticalText();
}
5.3 性能优化建议
- 批处理优化:将静态竖排文本合并为单个TMP对象
- 材质实例化:避免为每个竖排文本创建新材质
- 动态文本缓存:对频繁更新的文本使用对象池
六、进阶应用场景
6.1 混合横竖排文本
// 示例:同一TMP对象中部分横排部分竖排
public void SetMixedText(string horizontalText, string verticalText) {
textComponent.text = $"<align=center>{horizontalText}\n</align>";
// 实际实现需要更复杂的富文本处理或多个TMP对象组合
}
6.2 曲线竖排效果
通过修改顶点着色器中的position计算,可以实现沿路径排列的竖排文本:
// 在顶点着色器中添加路径计算
float2 pathPosition = CalculatePathPosition(i.worldPosition.x);
o.vertex.xy += pathPosition * _CurveStrength;
七、最佳实践总结
- 字体选择:优先使用支持CJK的字体(如思源黑体、Noto系列)
- 参数基准:
- 字号:24-32pt(移动端)
- 字符间距:30-50单位
- 行间距:1.3-1.8倍字高
- 性能基准:
- 单个场景竖排TMP对象不超过50个
- 动态文本更新频率控制在30fps以下
通过以上三种方案的灵活组合,开发者可以应对从简单静态文本到复杂动态效果的各类竖排需求。实际项目中建议从Inspector配置方案开始,遇到特殊需求时再考虑着色器或脚本方案。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权请联系我们,一经查实立即删除!