我正在制作一个游戏,我从XML文件中读取对话文本。我正在尝试制作一个例程以根据需要自动添加换行符,以便它适合文本框。不过,它只是无法正常工作。这是当前的代码:
SpriteFont dialogueFont = font31Adelon;
int lastSpace = 0;
string builder = "";
string newestLine = "";
float maxWidth = 921.6f;
float stringLength = 0;
for (int i = 0; i <= speech.Length - 1; i++) //each char in the string
{
if (speech[i] == ' ') //record the index of the most recent space
{
lastSpace = i;
}
builder += speech[i];
newestLine += speech[i];
stringLength = dialogueFont.MeasureString(newestLine).X;
if (stringLength > maxWidth) //longer than allowed
{
builder = builder.Remove(lastSpace); //cut off from last space
builder += Environment.NewLine;
i = lastSpace; //start back from the cutoff
newestLine = "";
}
}
speech = builder;
我的测试字符串是"这是一个必须正确分解为多行的长语音示例。它有几行长,并没有真正说出任何重要的东西,因为它只是示例文本。
这就是语音最终的样子:http://www.iaza.com/work/120627C/iaza11394935036400.png
我认为,第一行之所以有效,是因为它恰好是一个使其超出极限的空间。
i = 81 和 lastSpace = 80 是第二行结束的地方。生成器在 .删除命令:"这是一个长演讲的例子,\r必须分成多行c"
运行后,它看起来像这样:"这是一个长演讲的示例\r必须分成多行"
第三行在 i = 123 和 lastSpace = 120 时超过了大小限制。在 .删除:"这是一个长语音的示例\r必须正确地分解为多行\r。它有几行长,母鹿"
之后:"这是一个长语音的示例\r必须正确地分解为多行\r。它是几行长"
如您所见,它会切断一个额外的字符,即使字符 80(该空格)是它应该开始删除的位置。从我读到的.当使用单个参数调用时,删除所有内容,包括给定索引及其之后的内容。不过,它也削减了i = 79!似乎从 lastSpace 中添加或减去以弥补这一点应该很容易,但我要么得到"索引越界"错误,要么我切断了更多字符。我试过做.删除(lastSpace,i-lastSpace),这也不起作用。我尝试通过添加或减去lastSpace来处理"以空格结尾"的情况,与其他情况不同。我尝试过以不同的方式分解事物,但没有一种奏效。
我厌倦了看这个,任何帮助将不胜感激。
将Environment.NewLine
添加到StringBuilder
中,在指定开始删除的索引时需要考虑这一点。
Environment.NewLine
的值取决于系统。它可以是"rn"
、"n"
或"r"
(或者,根据MSDN,只有前两个中的一个)。
在您的情况下,它是"rn"
,这意味着要删除一个空格,您添加了另外两个字符。
首先,您需要声明一个新变量:
int additionalChars = 0;
然后,在添加一行文本时,您应该将代码更改为如下所示的内容:
builder = builder.Remove(lastSpace + additionalChars); //cut off from last space
builder += Environment.NewLine;
additionalChars += Environment.NewLine.Length - 1;
-1
是因为您已经删除了一个空格(应该使此代码独立于系统的Environment.NewLine
定义)。
更新:您还应该考虑超过行数限制的单词。无论如何,您都应该打破它们(忍不住尝试一下):
if (stringLength > maxWidth) //longer than allowed
{
// Cut off only if there was a space to cut off at
if (lastSpace >= 0) {
builder = builder.Remove(lastSpace + additionalChars); //cut off from last space
i = lastSpace; //start back from the cutoff
}
builder += Environment.NewLine;
// If there was no space that we cut off, there is also no need to subtract it here
additionalChars += Environment.NewLine.Length - (lastSpace >= 0 ? 1 : 0);
lastSpace = -1; // Means: No space found yet
newestLine = "";
}
作为另一种方法,您可以使用 .split 将句子分解为数组,然后填充您的框,直到没有空间进行下一个工作,然后添加换行符并从下一行开始。
你能做一些类似以下代码的事情吗?优点是双重的。首先,它跳到下一个空格来测量和决定是否添加整个单词,而不是一个字母一个字母。其次,它只为字符串中的每个单词调用一次 MeasureString,而不是为添加到字符串中的每个字母调用一次。它使用 StringBuilder Append
单词何时适合,或者AppendLine
不适合何时需要添加换行符。
int lastSpace = 0;
int nextSpace = s.IndexOf(' ', lastSpace + 1);
float width = 0;
float totalWidth = 0;
float maxWidth = 200;
while (nextSpace >= 0)
{
string piece = s.Substring(lastSpace, nextSpace - lastSpace);
width = g.MeasureString(piece, this.Font).Width;
if (totalWidth + width < maxWidth)
{
sb.Append(piece);
totalWidth += width;
}
else
{
sb.AppendLine(piece);
totalWidth = 0;
}
lastSpace = nextSpace;
nextSpace = s.IndexOf(' ', lastSpace + 1);
}
MessageBox.Show(sb.ToString());