最近自己开发的文字模拟经营游戏《航天计划》在steam正式发行,第一款游戏上架,好像有很多话想说,但又不知从何说起。最终决定讲讲开发中遇到的一些问题,希望能帮助到大家。
文字游戏不可避免的需要处理大量文字。我希望在游戏中介绍一些相关学科术语,具体来说,鼠标在术语上悬停会创造一个Panel来显示术语释义。
我用的方法是,在术语位置额外生成一个透明的对象,在对象上判断悬停时间、生成Panel的内容。那么问题来了,透明对象的坐标和尺寸需要恰好覆盖术语,术语的坐标(至少是局部坐标)是必需的。
遇到问题首先想到的是……百度。果真有朋友研究过这个问题。
public Vector3 GetPosAtText(Canvas canvas, Text text,string strFragment) { int strFragmentIndex = text.text.IndexOf(strFragment);//-1表示不包含strFragment Vector3 stringPos = Vector3.zero; if (strFragmentIndex>-1) { Vector3 firstPos = GetPosAtText(canvas, text, strFragmentIndex + 1); Vector3 lastPos= GetPosAtText(canvas, text, strFragmentIndex+strFragment.Length); stringPos = (firstPos + lastPos) * 0.5f; } else { stringPos= GetPosAtText(canvas, text, strFragmentIndex); } return stringPos; } ////// 得到Text中字符的位置;canvas:所在的Canvas,text:需要定位的Text,charIndex:Text中的字符位置 /// public Vector3 GetPosAtText(Canvas canvas,Text text,int charIndex) { string textStr = text.text; Vector3 charPos = Vector3.zero; if (charIndex <= textStr.Length && charIndex > 0) { TextGenerator textGen = new TextGenerator(textStr.Length); Vector2 extents = text.gameObject.GetComponent().rect.size; textGen.Populate(textStr, text.GetGenerationSettings(extents)); int newLine = textStr.Substring(0, charIndex).Split('\n').Length - 1; int whiteSpace = textStr.Substring(0, charIndex).Split(' ').Length - 1; int indexOfTextQuad = (charIndex * 4) + (newLine * 4) - 4; if (indexOfTextQuad < textGen.vertexCount) { charPos = (textGen.verts[indexOfTextQuad].position + textGen.verts[indexOfTextQuad + 1].position + textGen.verts[indexOfTextQuad + 2].position + textGen.verts[indexOfTextQuad + 3].position) / 4f; } } charPos /= canvas.scaleFactor;//适应不同分辨率的屏幕 charPos = text.transform.TransformPoint(charPos);//转换为世界坐标 return charPos; }
以上皆原文:https://www.cnblogs.com/Jason-c/p/10573567.html
方法分为两部分,第一部分获取指定字符在TEXT中的索引,第二部分根据索引获取对应字符渲染坐标。但原方法在我的项目中并不能很好运行,下面我来详细解释一下运作原理。
unity中TEXT文字的渲染过程,每个字符对应生成四角四个顶点。TextGenerator.Populate会立刻使用指定的字符串生成顶点。例如,TEXT内容为“今天周五。”,则TextGenerator.verts数量共5*4=20,利用position可以直接获取对应顶点的坐标。如果我想获取“五”左上角的坐标,“五”的文本索引为3,3*4=12,可以使用TextGenerator.verts[12].position。
一个容易忽视的问题在于,空格/换行/符号不进行渲染。例如,TEXT内容为“今天\n周五。”我仍然希望获取“五”左上角的坐标,换行符并不渲染,坐标仍为TextGenerator.verts[12].position,但“五”的文本索引却变成了4,此时计算真实索引时,需要减去指定字符以前所有换行符。对于符号而言(<i></i>),同样不参与渲染,但每个符号占多个索引位。一对<i></i>占据7个索引位。
因此原文的第二个方法,在计算indexOfTextQuad时是需要修改的,否则必定报错。这或许是unity更新的缘故。
此外,计算出的坐标是在TEXT组件对应对象的局部坐标系中。有需要可以进行转换。
暂无关于此日志的评论。