1

我正在制作游戏,我从 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 是第二行结束的地方。builder 在 .Remove 命令之前看起来像这样:“这是一个长演讲的例子,\r\n必须分成多行 c”

运行后它看起来像这样:“这是一个长演讲的例子,\r\n必须分成多行”

第三行超出了 i = 123 和 lastSpace = 120 的大小限制。在 .Remove 之前看起来像这样:“这是一个\r\n必须分成多行的长演讲示例\r\不正确。它有几行长,而且是"

和之后:“这是一个长演讲的例子,\r\n必须正确地分成多行\r\n。它有好几行”

正如你所看到的,它切断了一个额外的字符,即使字符 80,那个空间,是它应该开始删除的地方。从我所读到的.Remove,当使用单个参数调用时,会删除包括给定索引在内的所有内容。不过,它也切断了 i = 79!似乎应该很容易从 lastSpace 中添加或减去来弥补这一点,但我要么得到“索引超出范围”错误,要么我切断了更多的字符。我试过做 .Remove(lastSpace, i-lastSpace),但这也不起作用。我尝试通过添加或减去 lastSpace 来以不同于其他方式处理“以空格结尾”的情况。我尝试过以不同的方式分解事物,但都没有奏效。

我厌倦了看这个,任何帮助将不胜感激。

4

3 回答 3

1

作为一种替代方法,您可以使用 .split 将您的句子分成一个数组,然后填充您的框,直到没有空间进行下一项工作,然后添加换行符并从下一行开始。

于 2012-06-27T05:51:56.597 回答
1

添加Environment.NewLine到您的StringBuilder中,您需要在指定开始删除的索引时考虑这一点。

Environment.NewLine的值取决于系统。它可以是"\r\n","\n"或(或根据 MSDN"\r"的前两者之一)。 在您的情况下,这意味着要删除一个空格,您添加了另外两个字符。
"\r\n"

首先,您需要声明一个新变量:

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 = "";
}
于 2012-06-27T06:07:57.580 回答
0

你能做类似下面的代码吗?优点是双重的。首先,它跳到下一个空格来衡量并决定是否添加整个单词,而不是一个字母一个字母。其次,它只为字符串中的每个单词调用一次 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());
于 2012-06-27T07:02:20.553 回答