1.语序变化(从右往左阅读)
对于很多国家的阅读顺序与我们是相反的,所以在做本地化的时候就要考虑如何将文本正确的翻转。
有些国家的文本中带有一些特殊符号如:
Les Mise\u0301rables在Unity中会转换成Les Misérables,因为Unity内部使用Unicode进行文本存储。那么在字符串翻转时我们就要考虑在翻转后重音仍要在e上而不能被标记在r上。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
private static string ReverseString(string str) { if (string.IsNullOrEmpty(str) || str.Length == 1) return str; StringBuilder sb = new StringBuilder(); var enumerator = StringInfo.GetTextElementEnumerator(str); while (enumerator.MoveNext()) sb.Insert(0,(string)enumerator.Current); return sb.ToString(); } //result: //before : Les Misérables //after : selbarésiM seL |
这样就可以将文本正确翻转,但是考虑到运行时重新构建字符串会占用额外的内存,所以让我们在导出翻译表的时候就直接把文本翻转吧!~
2.文本纵向排列
修改文本组件顶点信息,重新计算顶点位置后将文本变为竖向排列。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 |
using UnityEngine; using UnityEngine.UI; using System.Collections.Generic; using System.Text.RegularExpressions; [ExecuteInEditMode] public class VerticalText : BaseMeshEffect { [Tooltip("字和字之间的距离")] public float spacing = 1; private float lineSpacing = 1; private float textSpacing = 1; private float xOffset = 0; private float yOffset = 0; private Text textGo; private Regex regex; protected override void OnEnable() { base.OnEnable(); if (textGo == null) textGo = GetComponent<Text>(); //不让垂直方向影响顶点位置 textGo.verticalOverflow = VerticalWrapMode.Overflow; regex = new Regex("<.*?>"); } void modifyText(VertexHelper helper, int i, int charYPos, int charXPos) { //根据下标取4个顶点信息 UIVertex lb = new UIVertex(); helper.PopulateUIVertex(ref lb, i * 4); UIVertex lt = new UIVertex(); helper.PopulateUIVertex(ref lt, i * 4 + 1); UIVertex rt = new UIVertex(); helper.PopulateUIVertex(ref rt, i * 4 + 2); UIVertex rb = new UIVertex(); helper.PopulateUIVertex(ref rb, i * 4 + 3); //算一下字体矩形的中心 Vector3 center = Vector3.Lerp(lb.position, rt.position, 0.5f); Matrix4x4 move = Matrix4x4.TRS(-center, Quaternion.identity, Vector3.one); float x = -charXPos * lineSpacing + xOffset; float y = -charYPos * textSpacing + yOffset; Vector3 pos = new Vector3(x, y, 0); Matrix4x4 place = Matrix4x4.TRS(pos, Quaternion.identity, Vector3.one); Matrix4x4 transform = place * move; lb.position = transform.MultiplyPoint(lb.position); lt.position = transform.MultiplyPoint(lt.position); rt.position = transform.MultiplyPoint(rt.position); rb.position = transform.MultiplyPoint(rb.position); //把顶点设置回去 helper.SetUIVertex(lb, i * 4); helper.SetUIVertex(lt, i * 4 + 1); helper.SetUIVertex(rt, i * 4 + 2); helper.SetUIVertex(rb, i * 4 + 3); } public override void ModifyMesh(VertexHelper helper) { if (!IsActive() || textGo == null) return; //当组件范围小于字体大小时直接return var size = textGo.rectTransform.rect.size; if (size.y < textGo.fontSize || size.x < textGo.fontSize) return; //剔除富文本标签 string targetStr = regex.Replace(textGo.text, ""); //计算列间距与字间距 lineSpacing = textGo.fontSize * textGo.lineSpacing; textSpacing = textGo.fontSize * spacing; xOffset = size.x / 2 - textGo.fontSize / 2; yOffset = size.y / 2 - textGo.fontSize / 2; //重新计算一版排版,默认高度为一个文字高度 int row = 0, col = 0, index = 0; float height = textGo.fontSize; int vertexCount = helper.currentVertCount / 4; for (int i = 0; i < targetStr.Length; i++) { if (index >= vertexCount) return; //标志位,防止因为刚好文本需要换行的时候输入了\n导致换了两次行 bool colAdded = false; //当文本高度超过组件范围,且本行不是空行的时候才换行 if (height > size.y) { col++; row = 0; height = textGo.fontSize; colAdded = true; } //根据字符计算位置,空字符时不修改顶点,只计算高度和行数 //目前文字的位置只与row相关,如果需要空格占半个字符位,需要修改对应位置计算 switch (targetStr[i]) { case '\n': if (!colAdded) { col++; row = 0; height = textGo.fontSize; } continue; case '\u00A0': case '\u0020': row++; height += textGo.fontSize; break; case '\t': row += 2; height += textGo.fontSize * 2; break; default: modifyText(helper, index, row, col); row++; height += textGo.fontSize; index++; break; } } } } |
验证性能时发现:ModifyMesh函数只有在组件重绘时才会执行,单次执行时间不到1ms,所以性能来说应该还可以。内存消耗大概在20kb左右,还有提升空间。