2
\$\begingroup\$

I'm trying to create a simple GUI system and am currently stuck on how to implement a textarea with a scrollbar. In other words, the text is too large to fit into the view area. I want to learn how to do this, so I'd rather not use an already rolled API.

I believe this could be done if the text were part of a texture, but if the game had a lot of unique dialog, this seems expensive.

I researched creating a texture on the fly and writing to it, but came up with nothing.

Any suggested strategies would be appreciated. I believe it boils down to: text in a texture and how? Or something I have not thought of...

\$\endgroup\$
2
  • \$\begingroup\$ How are you going to be rendering your text? \$\endgroup\$
    – Cypher
    Commented Nov 5, 2012 at 17:44
  • \$\begingroup\$ Whether in a texture or a string, I'd use the SpriteBatch. If there's some other way, I'm not yet aware of it. \$\endgroup\$ Commented Nov 5, 2012 at 17:54

1 Answer 1

1
\$\begingroup\$

You've basically got two problems to solve here.

First of all, you need to offset your text - so that it moves around based on where the scrollbar moves. You can do this by passing a transformation matrix to SpriteBatch.Begin, or simply adding and offset to the position when you call SpriteBatch.Draw.

Usually using a matrix is preferred, as you don't have to correctly pass the offset in multiple places.

The second issue to solve is to clip your text, so that it's not drawing outside of the box that you want to draw it in. You can achieve this by either setting a viewport or a scissor rectangle.

A viewport involves setting GraphicsDevice.Viewport (and setting it back when you're done). This affects drawing coordinates - SpriteBatch, for example, puts (0,0) at the top-left of the viewport.

Setting a scissor rectangle requires both setting GraphicsDevice.ScissorRectangle and creating and using a RasterizerState that has ScissorTestEnable = true. It does not affect coordinates - it simply clips.

(Rendering text to a render target and drawing that would work - but it's both complicated and relatively slow.)

\$\endgroup\$
5
  • \$\begingroup\$ As far as the breaks in the string content go, are those manually added in (usually) or does the programmer rig up some way to add them programatically? It would seem the latter, so the app would be flexible enough to handle font changes, but I'm not seeing how to do it right now... \$\endgroup\$ Commented Nov 9, 2012 at 20:05
  • \$\begingroup\$ Do you mean word-wrap? Usually you compute that at run-time. \$\endgroup\$ Commented Nov 10, 2012 at 2:24
  • \$\begingroup\$ I currently have a ScreenManager which calls a Draw() method on all of it's Screens, which in turn call a Draw() method on all of the Widgets they own. All of this happens in one SpriteBactch and it seems that's not going to work anymore due to the need for a special scissor SpriteBatch. How is this usually handled? Surely each Widget can't have it's own SpriteBatch? But since the needs of the individual Widgets differ, perhaps so? \$\endgroup\$ Commented Nov 11, 2012 at 12:40
  • \$\begingroup\$ After doing some more reading I see that calling End() executes the drawing of the batch, so any scheme of nested batches is just going to end up drawing over the others. I would imagine I need a flattened list of 'normal' Widgets and a list of 'scissor' widgets and process the two groups in separate SpriteBatches, one after the other. \$\endgroup\$ Commented Nov 11, 2012 at 14:10
  • 1
    \$\begingroup\$ I got it working: I now have one SpriteBatch and swap out the RasterizerState when I need to do a scissor. \$\endgroup\$ Commented Nov 11, 2012 at 15:26

You must log in to answer this question.

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