4
\$\begingroup\$

I am trying to do an appication in monogame windows. I have a long text to be displayed on screen. I tried to render it on screen using spriteBatch.Drawstring, was succesful to an extent. But, the text did not fit into a required area. I had followed this tutorial. I need a vertical scroll to be implemented to have the entire text inside my desired area. Can anyone suggest some help. This is my current code :

protected override void LoadContent()
    {
        spriteBatch = new SpriteBatch(GraphicsDevice);
        _boxTexture = new SolidColorTexture(GraphicsDevice, Color.Red);
        _borderRectangle = new Rectangle(100, 100, 500, 500);
        _textboxRectangle = new Rectangle(105, 105, 490, 490);
        _font = Content.Load<SpriteFont>("Rockwell");
        _text = "He determined to drop his litigation with the monastry, and relinguish his claims to the wood-cuting and fishery rihgts at once. He was the more ready to do this becuase the rights had becom much less valuable, and he had indeed the vaguest idea where the wood and river in quedtion were.";

    }

private String parseText(String text)
{
String line = String.Empty;
String returnString = String.Empty;
String[] wordArray = text.Split(' ');

foreach (String word in wordArray)
{
    if (font.MeasureString(line + word).Length() > textBox.Width)
    {
        returnString = returnString + line + '\n';
        line = String.Empty;
    }

    line = line + word + ' ';
}

return returnString + line;
}

and inside draw function :

spriteBatch.DrawString(font, parseText(text), new Vector2(textBox.X, textBox.Y), Color.White);
\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

I wrote something similar to this for the GUI library I made. It's hosted here and uses the MIT license so feel free to rip anything you want out of it.

This method draws the text to a render target as I found that provided significant performance gains compared to redrawing everything line by line. Simply replace the textureBaker bit with your SpriteBatch if you want to redraw normally.

For the scrolling bit simply use the clipping rectangle GraphicsDevice.ScissorRectangle = node.Data.ClippingArea; to limit what is drawn. If you want help on how to handle the scrolling as in the rendering of scrollbars and handling input I can show you how I accomplished that but it is fairly involved and would warrant a separate question. If you want to take a look here are the relevant bits: Handling Input, Layout and Logic.

    public void BakeText() {

        var textureBaker = new TextureBaker(
            RenderManager.GraphicsDevice,
            Area.Width,
            Area.Height,
            TextureBaker.RenderState.Fill);

        var start = 0;
        var height = 0.0f;

        while (true) {

            start = RenderLine(textureBaker, start, height);

            if (start >= Length) {
                RenderedText = textureBaker.GetTexture();
                return;
            }

            height += Font.LineSpacing;
        }
    }

    private int RenderLine(SpriteBatch textureBaker, int start, float height) {

        var breakLocation = start;
        var lineLength = 0.0f;
        var row = (byte)(height / Font.LineSpacing);
        string text = new string(_char), tempText;

        //Starting from end of last line loop though the characters
        for (var iCount = start; iCount < Length; iCount++) {

            //Calculate screen location of current character
            _charX[iCount] = (short)lineLength;
            _charY[iCount] = (short)height;
            _row[iCount] = row;

            //Calculate the width of the current line
            lineLength += _charWidth[iCount];

            //Current line is too long need to split it
            if (lineLength > Area.Width) {
                if (breakLocation == start) {
                    //Have to split a word
                    //Render line and return start of new line
                    tempText = text.Substring(start, iCount - start);
                    textureBaker.DrawString(Font, tempText, new Vector2(0.0f, height), TextRenderer.Color);
                    return iCount + 1;
                } else {
                    //Have a character we can split on
                    //Render line and return start of new line
                    tempText = text.Substring(start, breakLocation - start);
                    textureBaker.DrawString(Font, tempText, new Vector2(0.0f, height), TextRenderer.Color);
                    return breakLocation + 1;
                }
            }

            //Handle characters that force/allow for breaks
            switch (_char[iCount]) {
                //These characters force a line break
                case '\r':
                case '\n':
                    //Render line and return start of new line
                    tempText = text.Substring(start, iCount - start);
                    textureBaker.DrawString(Font, tempText, new Vector2(0.0f, height), TextRenderer.Color);
                    return iCount + 1;
                //These characters are good break locations
                case '-':
                case ' ':
                    breakLocation = iCount + 1;
                    break;
            }
        }

        //We hit the end of the text box render line and return
        //_textData.Length so RenderText knows to return
        tempText = text.Substring(start, Length - start);
        textureBaker.DrawString(Font, tempText, new Vector2(0.0f, height), TextRenderer.Color);
        return Length;
    }        
}
\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .