问题
I have one long string and I want to split it in a few pieces so that every line of the text is always in the given rectangle. The text should not exceed the border of the rectangle.
The height of the rectangle isn't the problem. The text will never touch the bottom of the rectangle because the rectangle is very tall. But the rectangle isn't very wide.
How can I calculate which parts of the string should be drawn in each line? I don't want to split a word. If a word exceeds the border of the rectangle, then the word should be drawn in the next line.
For example, drawing the string should look like this:
Cyberpunk 2077 is an upcoming role-playing video game
developed and published by CD Projekt, releasing for
Google Stadia, Microsoft Windows, PlayStation 4, and
...
and not like that:
Cyberpunk 2077 is an upcoming role-playing video game devel
oped and published by CD Projekt, releasing for Google Stad
ia, Microsoft Windows, PlayStation 4, and Xbox One on 16
...
Right now, spriteBatch is drawing the full long string like that in just one line and the text exceeds the border of the rectangle. How can I split it up correctly in a few lines?
Cyberpunk 2077 is an upcoming role-playing video game developed and published by CD Projekt, releasing for Google Stadia, Microsoft Windows, PlayStation 4, and Xbox One on 16 April 2020. Adapted from the 1988 tabletop game Cyberpunk 2020, it is set fifty-seven years later in dystopian Night City, an open world with six distinct regions. In a first-person perspective, players assume the role of the customisable mercenary V, who can reach prominence in hacking, machinery, and combat. V has an arsenal of ranged weapons and options for melee combat.
I use spriteBatch.DrawString to draw the string:
string Text = "Cyberpunk 2077 is an upcoming role-playing video game developed and published by CD Projekt, releasing for Google Stadia, Microsoft Windows, PlayStation 4, and Xbox One on 16 April 2020. Adapted from the 1988 tabletop game Cyberpunk 2020, it is set fifty-seven years later in dystopian Night City, an open world with six distinct regions. In a first-person perspective, players assume the role of the customisable mercenary V, who can reach prominence in hacking, machinery, and combat. V has an arsenal of ranged weapons and options for melee combat.";
protected override void Draw(GameTime gameTime)
{
graphics.GraphicsDevice.Clear(Microsoft.Xna.Framework.Color.CornflowerBlue);
spriteBatch.Begin();
spriteBatch.DrawString(Font, Text, new Vector2(200, 300), Microsoft.Xna.Framework.Color.White, 0, Vector2.Zero, 1f, SpriteEffects.None, 0f);
spriteBatch.End();
base.Draw(gameTime);
}
UPDATE: You need to add this line of code at the end:
yield return buffer;
string[] lines = Split(Text, 400, Font).ToArray();
public static IEnumerable<string> Split(string text, double rectangleWidth, SpriteFont font)
{
var words = text.Split(' ');
string buffer = string.Empty;
foreach (var word in words)
{
var newBuffer = buffer + " " + word;
if (word == words[0])
newBuffer = word;
else
newBuffer = buffer + " " + word;
Vector2 FontMeasurements = font.MeasureString(newBuffer);
if (FontMeasurements.X >= rectangleWidth)
{
yield return buffer;
buffer = word;
}
else
{
buffer = newBuffer;
}
}
yield return buffer;
}
Drawing:
for (int i = 0; i <= lines.Count() - 1; i++)
spriteBatch.DrawString(Font, lines[i], new Vector2(300, 500 + i * 30), Microsoft.Xna.Framework.Color.White, 0, Vector2.Zero, 1f, SpriteEffects.None, 0f);
or:
string boxedText = string.Join('\n', Split(Text, 400, Font));
spriteBatch.DrawString(Font, boxedText, new Vector2(300, 500), Microsoft.Xna.Framework.Color.White, 0, Vector2.Zero, 1f, SpriteEffects.None, 0f);
回答1:
Assuming you have a Method Measure(string text)
which returns the actual visual width of the text (not needed if you use a monospaced font), you could use this method to split the text into lines:
public static IEnumerable<string> Split(string text, double rectangleWidth)
{
var words = text.Split(' ');
string buffer = string.Empty;
foreach (var word in words)
{
var newBuffer = buffer + " " + word;
if (Measure(newBuffer) >= rectangleWidth)
{
yield return buffer;
buffer = word;
}
else
{
buffer = newBuffer;
}
}
yield return buffer;
}
To get the lines as an array, use string[] lines = Split(text, Rectangle.Width).ToArray()
.
If you want a single string separated by newlines, use string boxedText = string.Join('\n', Split(text, Rectangle.Width))
.
In your case you would use it like this:
string Text = "Cyberpunk 2077 is an upcoming role-playing video game developed and published by CD Projekt, releasing for Google Stadia, Microsoft Windows, PlayStation 4, and Xbox One on 16 April 2020. Adapted from the 1988 tabletop game Cyberpunk 2020, it is set fifty-seven years later in dystopian Night City, an open world with six distinct regions. In a first-person perspective, players assume the role of the customisable mercenary V, who can reach prominence in hacking, machinery, and combat. V has an arsenal of ranged weapons and options for melee combat.";
protected override void Draw(GameTime gameTime)
{
graphics.GraphicsDevice.Clear(Microsoft.Xna.Framework.Color.CornflowerBlue);
spriteBatch.Begin();
spriteBatch.DrawString(
Font,
string.Join(' ', Split(Text, Rectangle.Width)),
new Vector2(200, 300),
Microsoft.Xna.Framework.Color.White,
0,
Vector2.Zero,
1f,
SpriteEffects.None,
0f);
spriteBatch.End();
base.Draw(gameTime);
}
来源:https://stackoverflow.com/questions/57715767/how-can-i-split-a-long-string-so-that-it-matches-with-a-given-rectangle