Tuesday, November 13, 2007

How to Print Simple Text onto the Screen

Most games need to be able to render text on the screen. Since many people would like to know how to do this, I’ve decided to write a small tutorial on this subject.

Text in itself is rendered onto the screen in the same way as a texture; through a bitmap image. On this image, every letter and symbol has its own small area. Before XNA 1.0 came out, I saw text being rendered through someone using their own system where a string is dissected and then each letter is drawn separately. Fortunately for us though, XNA 1.0 gives us the SpriteFont. This name refers both to an XML file and a C# class.

As said before, to render text follows almost the same concepts as rendering textures. The steps in the process are few and simple:

  1. Create a SpriteFont XML file and specify the needed properties.

  2. Load the SpriteFont file using the Content Pipeline, into a SpriteFont class.

  3. Render text using the specified SpriteFont and a shader (we use the SpriteBatch).

From these steps it is very easy to recognize the similarity between rendering textures and rendering text.

Creating the SpriteFont
So the first step to implementing a certain font is to create that font. This can be accomplished using the SpriteFont XML file. Inside of the Solution Explorer, right click on your project and click Add / New Item.


Figure 1: Right Click on your project name and click Add / New Item.

Note: A default Windows Game template is used with the namespace of WindowsGame1. It is not in the scope of this lesson to explain about project templates though.

You should now be taken to a page where you can choose what you want to create. We want to create a SpriteFont. Click on that template and name the SpriteFont, “Verdana”.


Figure 2: Create a SpriteFont named “Verdana”.

After clicking Add, in your Solution Explorer you will see the Verdana.spritefont file in your list. This file is already opened. If you take a quick look around the file you will notice several different XML tags specifying the different properties of the font. These properties are as follows:

  • FontName: This property changes the font family of the font (i.e. Times New Roman, Verdana, etc.).
  • Size: This property changes the size of the font.
  • Spacing: This property changes the amount of spacing in between the characters of the text. Usually, you can leave this as the default value of two.
  • Style: This property changes the appearance of your text. You can enter “Regular” for no changes; “Bold” for bolded text; “Italic” for italicized text; or finally, “Bold, Italic” for both bolded and italicized text. Unfortunately, there is not ability for underlined text.

For our simple purposes, we will leave the font properties as they are.

Note: If understanding the XML is confusing, do not worry. That is not necessary as long as you know what text you change. For all tags there is a common structure: [name]text[/endname] Where you want to place the code is where the “text” would be; in between the name and endname tags.

Code Note: For the rest of the tutorial, open and close brackets will be used to replace open and close tags. I cannot use tags in the text due to the HTML problems.

Using the Content Pipeline to Create a SpriteFont Class
Now that we have our SpriteFont file created, we can load it into a SpriteFont class. This class will then be used to draw a specified string along with the help of the SpriteBatch class.
The first step is to create a variable for the SpriteFont. At the top of the class where the GraphicsDeviceManager and ContentManager are created, add this code:

//The SpriteFont to hold the Verdana XML font.
SpriteFont verdanaFont;

Next, we can initialize this variable. Similar to a Texture2D, instead of calling the constructor of the SpriteFont class (which is virtually useless) we instead directly load it with an outside file using content.Load(). We want to place this code into the LoadGraphicsContent method (so that it can be re-loaded when necessary), specifically inside of the if (loadAllContent) statement:

//Init the SpriteFont with a real SpriteFont file
//from the Solution Explorer.
verdanaFont = content.Load[Texture2D]("Verdana");


Code Note: Switch the two forward and backward slashes for tags. I couldn't use tags in this post because of the HTML. This code practice will be used for the rest of the tutorial.

This code first calls the Load method of the ContentManager variable content and tells it to load a SpriteFont. Then, we pass in the name of the SpriteFont XML file. Notice that we remove the file extension (i.e. .spriteFont).

Note: The reason why we load the SpriteFont inside of the LoadGraphicsContent method is not to be explained in this lesson. For now you don’t really need to know anyway.

Rendering Text onto the Screen Using the SpriteBatch
Finally, we have come to the part where we can render text onto the screen. As said earlier, a font is exactly the same in that it is a bitmap image that needs to be rendered. The SpriteBatch class, which is commonly used to render textures, can also be used along with its DrawString method to render text. Note that, the SpriteBatch actually draws the text. All the SpriteFont does is hold the value of what the text will look like.

Since we first need a SpriteBatch to begin drawing, add this code to the top of your class along with the other variable declarations. This code creates a SpriteBatch variable.


//The SpriteBatch used to draw the text.
SpriteBatch spriteBatch;

Now we want to initialize this variable. Inside of the Initialize method, place this code:

//Initialize the SpriteBatch.
spriteBatch = new SpriteBatch(graphics.GraphicsDevice);

The SpriteBatch constructor needs a GraphicsDevice class in order to be initialized. The GraphicsDeviceManager graphics has a GraphicsDevice in it, so we just use that.

Finally, we can draw the text. Using the SpriteBatch class and the SpriteFont class, we can render any string that we want. Inside of the Draw method, after the graphics.GraphicsDevice.Clear(Color.CornflowerBlue); line, add this code.

/*Start the SpriteBatch. This call is required to set different options. For us, we don't need any special modes so we call the zero-parameter method.*/

spriteBatch.Begin();

/*Draw the font. We pass in the SpriteFont to use, the string to draw, the position, and the color of the text.*/

spriteBatch.DrawString(verdanaFont, "Look at me!!", new
Vector2(100, 100), Color.Black);

/*Finally, end the SpriteBatch. For better processing results, all things to draw are placed in a list. When we call End, we draw all these things at once. Also, we return the different changed parameters back to their default values.*/

spriteBatch.End();

This code may seem confusing, but it can be easily divided into three simple parts.

First, we start the SpriteBatch. This is needed so that we can set different render-states for the device such as alpha-blending (transparency), or the way you want sprites to be sorted.

Then, you draw the SpriteBatch. This is the most important part of the code. In this call, we pass in several different parameters. First, we pass in the SpriteFont to be used. For us we passed in our Verdana font. Next, there is the actual string to draw. This can be anything you want. After this we pass in the position. The position is stored as a Vector2. We pass in 100, 100, which is just a little off of the top-left corner of the screen. Note that the top, left corner of the first letter of the string will be drawn at 100, 100. To change this you need to change the origin of where the text is drawn. Finally, we have the color of the text which mostly explains its purpose by its name.

The last part of the code is the call to end the SpriteBatch. As mentioned in the comments, it would be very inefficient to render each sprite whenever a Draw call was made. For this reason, all sprites to be drawn are put into a list. When the End method is called, all the sprites in the list are drawn at once. Also, once all the sprites are drawn, the different render-states for the device are reset back to their original values.

The Final Results
Finally, we can see the results of our work. If you run the project (F5), you should see something very similar to this:


Figure 3: The results of our efforts. Simple text printed onto the screen.

Hopefully, now you will see, “Look at me!!” written onto the screen. If you do not see these results or if you are confused or found an error, please post a comment so that I can fix it. I do hope this helped you with in your programming quest.

1 comment:

MLM said...

Thanks for the tut! I am just getting started with making a game and this helped me understand draw and text better.