11/17/07

VB.NET XNA Tutorial 8: Text

[GSE 1.0 Refresh]

Text as sprites

In XNA, text gets drawn to the screen in much the same way everything else in our 2D engine is being drawn to the screen: by having SpriteBatch draw sprites.

In order to put "Hello world!" on the screen, we'll need 8 regular sprites that just happen to look like characters. Specifically, we'll need the following sprites that look like:

  • H
  • e
  • l (we can use this one 3 times)
  • o (can be used twice)
  • w
  • r
  • d
  • !
Once we've made those sprites (and loaded them into the game), the next step will be to meticulously draw each one, in the right order, in the right place with perfect spacing, so when we're done we end up with words (and don't forget to offset "world!" from "Hello" to simulate a space character between them).

Sound tedious? How about an RPG with ten thousand lines of dialog. Sound daunting? If so, good! You're ready to appreciate the fact XNA can do all of the aforementioned work for you. Not only will it line up the little sprites on the screen for you, it can even create all the sprites for you.

MSBuild & SpriteFont

All we've asked MSBuild to do for us so far is convert our texture content (.png or .jpg, etc.) into .xnb files. The .xnb file format is a "cross-platform" file that can be used on either Windows or the Xbox360. In light of the known compatibility issues with VB.NET and the .NET framework found on the XBox360, why are we bothering to use MSBuild to produce a "cross-platform" file, anyway?

If you're making an XNA app exclusively for Windows, ending up with "cross-platform" content is somewhat incidental (a side-effect of the process). On the other hand, a distinct advantage to using MSBuild and the ContentManager can be found in SpriteFonts.

A SpriteFont starts out life as a small XML file with a ".spritefont" extension that you place in your content folder. The same MSBuild process that takes our texutre images and creates .xnb files can also take a .spritefont file to create another .xnb file - one that contains the characters of a specific font, at a specific size, as described by the contents of the .spritefont XML file. Here's an example of a .spritefont XML file:

<?xml version="1.0" encoding="utf-8"?>
<!--
This file contains an xml description of a font, and will be read by the XNA
Framework Content Pipeline. Follow the comments to customize the appearance
of the font in your game, and to change the characters which are available to draw
with.
-->
<XnaContent xmlns:Graphics="Microsoft.Xna.Framework.Content.Pipeline.Graphics">
<Asset Type="Graphics:FontDescription">

<!--
Modify this string to change the font that will be imported.
-->
<FontName>Arial</FontName>

<!--
Size is a float value, measured in points. Modify this value to change
the size of the font.
-->
<Size>14</Size>

<!--
Spacing is a float value, measured in pixels. Modify this value to change
the amount of spacing in between characters.
-->
<Spacing>2</Spacing>

<!--
Style controls the style of the font. Valid entries are "Regular", "Bold", "Italic",
and "Bold, Italic", and are case sensitive.
-->
<Style>Regular</Style>

<!--
CharacterRegions control what letters are available in the font. Every
character from Start to End will be built and made available for drawing. The
default range is from 32, (ASCII space), to 126, ('~'), covering the basic Latin
character set. The characters are ordered according to the Unicode standard.
See the documentation for more information.
-->
<CharacterRegions>
<CharacterRegion>
<Start>&#32;</Start>
<End>&#126;</End>
</CharacterRegion>
</CharacterRegions>
</Asset>
</XnaContent>

The C# Express IDE has native support for creating new .spritefont files, you just right-click the project and add one like you were adding a class file. With VB.NET, it's pretty much just as easy. There's no magic here, it's just an XML file. You can bring in an existing .spritefont file from disk, or just make a new text document item in your project, paste in the above code, and rename the file so it has a .spritefont extension. If you place it somewhere in your content folder, the VBContentManager understands to harvest .spritefont files and send them along to MSBuild. Similar to Textures, SpriteFonts are processed by MSBuild and the result is stored onto the VBContentManager as a SpriteFont object in the Fonts hashtable.

Implementation with the VBContentManager

Ok, so how do we use this "SpriteFont object" to get text onto the screen? It's a lot like drawing a texture; the SpriteBatch has a Draw() method for drawing textures, and it has a DrawString() method for drawing text to the screen. The DrawString() method accepts your SpriteFont object as a parameter (as well the text to render using the font, where to render it at, and what color to make it)


 'Draws "Hello world!" to the screen, using whatever font definition is found in
 'the file "test.spritefont" from the content folder.  Draws the string at the
 'upper-left corner of the screen in yellow.

 Me.objSB.Begin()

 Me.objSB.DrawString(Me.objCM.Fonts("test"), "Hello world!", Vector2.Zero, Color.Yellow)

 Me.objSB.End()


Without too much fuss, you'll just get the result you expect.

SpriteFont objects feature the MeasureString() method, which you may be familiar with already as it appears elsewhere in .NET, outside of XNA. MeasureString() is just a way to get the width and height of any string (but in a particular font and size), which can be handy for string-size related math (like centering text on the screen, for example).

In the screenshot below, I've placed a sprite font file in my project's Content\Fonts folder called test.spritefont. Test.spritefont specifies Arial at a size of 30. In the main draw loop of the game, I retrieve the SpriteFont object from the game's VBContentManager.Fonts hashtable, and use it's MeasureString method (in conjunction with the BackBufferWidth and BackBufferHeight) to center the text on the screen when calling SpriteBatch.DrawString:





A few quick extras re: the creation of SpriteFont files:

Mono-spaced fonts are not supported by Game Studio Express 1.0 (refresh) (the current version when I wrote this article). Last I heard, mono-spaced font support should make it into Game Studio 2.0.

As an aside, it's probably a reasonable speculation to guess that, due to Game Studio 2.0's compatibility with Visual Studio, it may be possible to simply add a SpriteFont file directly to a VB.NET XNA project after GS 2.0 is released (rather than having to "make your own"). Either way, we would continue to rely on something like the VBContentManager to invoke the MSBuild process in order to get the .xnb file created for us.

And finally, if you are interested in going beyond using the plain old fonts installed on your system, read this. My VBContentManager doesn't support what's discussed there, but you could certainly perform a quick & dirty modification along the lines of "if you find a texture in the fonts folder..." sort of thing.

0 comments: