XNA programs are capable of drawing very
high-resolution images, and you can use this ability to display text.
1. Text as a Resource
Before you can start
drawing text on the Xbox, you need to understand just how computers
manage character designs. The design of the shape of the characters is
described in a font file. Microsoft
Windows provides a very large number of these font files. The shape of
the text that you are reading now is described in a font called "Segoe."
Windows also provides a font called "Arial," and "Courier New," used here for program listings.
The font file gives the
shape of each of the characters. When a character shape is needed for
either printing on paper or drawing on the screen, the font data is used
to draw this shape at the required size. To get an XNA program to
display text in a particular font, you need to add a reference to that
font file to the program project. You then use the XNA Content
Management System to bring the font into the program for use when you
want to draw text.
2. Creating the XNA Clock Project
You create the project (called BigClock) using the New Project dialog box as you’ve done for all your previous projects. Note that the Create Directory For Solution option is selected in this
dialog box. Whenever you create a project, you should ensure that this
option is selected.
3. Adding a Font Resource
Figure 1 shows how to add a new resource to a game project. In Solution Explorer, right-click the Content item in the BigClock project, then select Add, New Item.
You can add a number of different kinds of new items to a project. Figure 2 shows the dialog box that lets you select the kind of item you wish to add.
The
range of items that you can add to your project depends on how many
other Microsoft Visual Studio components you have installed. You might
have more items available than those shown in Figure 2.
If you select the Sprite Font item, you can create a sprite font
reference. When you do this, you find that XNA Game Studio has filled in
the Name information at the bottom of the dialog box with
SpriteFont1.spritefont. This is the name that you use within your
program to refer to this item of font content. We are going to use this
for now, but in later games, you might want to change it to a name that
has a bit more meaning.
When Visual Studio builds the BigClock project, it reads an existing font on your Windows PC to build the SpriteFont that is used when the game runs. When a new font resource is created, it is initially set to use a font called Kootenay, which is supplied with XNA Game Studio.
You can use a different
font if you want, but if the name you give does not match a font that’s
installed on your computer, you won’t be able to build your program
because the Content Manager will be unable to find the requested item.
You can have more than
one font in your game if required, but you need to add each font that
you want to use as another resource. Remember, though, that adding extra
fonts makes your output program bigger because the character designs
need to be made part of the program. The name that you give must match a
font available on the computer that’s being used to build the game
because the XNA Content Manager uses the font file on the host computer
to build the sprite design for use in your XNA program.
Figure 3
shows the font item in Solution Explorer in XNA Game Studio as added to
the project. If you select this item in Solution Explorer and open it
by double-clicking it, you can see that it’s a file describing the font
that’s to be used in your program.
Note:
It’s
important you understand what’s happening here. When you add a resource
to a project, you simply add a reference to the item that you want to
use. You can think of the reference as an item on a shopping list. Just
like an item on a shopping list would remind you to buy a new toothbrush
the next time you were shopping, a resource reference tells the Content
Manager that a certain resource must be fetched when the program is to
be built.
When the project is
built, the Content Manager follows the reference to the required item
and then adds it to the program that’s being built. The purpose of the
resource information is to tell the Content Manager what to retrieve and
how to use the resource in the project.
This reference file is not written in C#, nor is it plain text. It’s written in a format called Extensible Markup Language (XML).
3.1. The XML File Format
A markup language is used
to describe things. It contains the names of these things and
information about them. As its name indicates, XML is extensible, so you
can use it to describe just about anything. As an example, a snippet of
XML that describes a high score might look as follows:
<?xml version="1.0" encoding="us-ascii" ?>
<highscore game="Breakout">
<playername>Rob Miles</playername>
<score>1500</score>
</highscore>
This high score
information is for the Breakout game; it shows the name of the player
and the score the player reached. The format of the lines and the way
that the open bracket (<) and close bracket (>) characters are
used to denote the names of the values and the values themselves are
defined in the XML standard. The first line of the snippet identifies
which version of XML you’re using for the rest of the data. The nice
thing about XML is that it’s easy for
non-computers to understand the content, and it’s a very
well-established way in which computer software can exchange
information.
In the case of your
font, the XML tells the Content Manager the name of the font to fetch,
the size of the font, whether it’s to be drawn as bold or italic, and
other font-related information. You don’t need to worry too much about
what’s in this file at the moment, but you can take a look if you wish.
Later, you’ll edit the content of this file to change the size of the
characters that are drawn.
4. Loading a Font
The Content Manager
fetches a font and make it available for use in a very similar way to
the images that you’ve used before. Each character design is delivered
to your program as a little image that the Draw method displays on the screen. For your clock, the game world consists of a variable called font, which is of type SpriteFont. This holds a reference to the font the program will have loaded. SpriteFont is another XNA type (there are many more). Your SpriteFont
will hold information about a font that the Content Manager loads for
you. You can declare the variable for the game world as follows:
// Game World
SpriteFont font;
The font can be loaded in the LoadContent method:
protected override void LoadContent()
{
// Create a new SpriteBatch, which can be used to draw textures.
spriteBatch = new SpriteBatch(GraphicsDevice);
font = Content.Load<SpriteFont>("SpriteFont1");
}
At this point, you might
be experiencing déjà vu or at least think you’ve seen this code before.
The pattern is the same as when you loaded your images, and even the
name of the method is the same. However, this time you’re using the
generic Load method to fetch a SpriteFont rather than a Texture2D
element. There is some strong programming magic at work here, but
fortunately you don’t need to worry about this at the moment; all you
need to know is that the Load method gets
whatever type it is asked to fetch. Later, you’ll create some games that
contain textures, fonts, and sounds, and for each type, the Load method behaves in an appropriate manner.
5. Drawing with a Font
Now that you have your font, you can draw with it. Remember that when you used the textures in this article, you used a Rectangle to tell the Draw method where to place the texture. However, when drawing text, you don’t do this. Instead, you use a vector, which tells the Draw
method where on the screen to start. "Vector" is a fancy word that
means "direction and distance." You’re using the 2-D (x and y value)
version of the vector. Games that work in 3-D space use values of x, y,
and z (where z is the depth value).
A 2-D vector is given as
two coordinates: the x value and the y value. It’s a bit like a treasure
map that pirates used. A pirate would say, "Start ye at the Old Oak
Tree and take ye twenty paces East and thirty paces South, and there ye
shall find my treasure chest." The vector says, "Start at the origin and
move 20 units across and 30 units down." If you think about it, this
means that a vector indeed specifies a direction so that a very smart
pirate could work out that she could "cut corners" and get to the
treasure more quickly by moving in the appropriate direction. Figure 4 shows how this would work, with a line showing the direct path to Blackbeard’s treasure.
In a text-drawing
program, you’re using a vector like a coordinate in that it specifies
the top left corner of the text you’re about to draw. You feed it into
the DrawText method as follows:
protected override void Draw(GameTime gameTime)
{
graphics.GraphicsDevice.Clear(Color.CornflowerBlue);
Vector2 textVector = new Vector2(20, 30);
spriteBatch.Begin();
spriteBatch.DrawString(font, "Hello World", textVector, Color.Red);
spriteBatch.End();
base.Draw(gameTime);
}
You’ve placed the top
left corner of the text at the spot 20 pixels across the screen and 30
pixels down. The text that you’re writing is the famous string "Hello
World," which is, by one of the laws of the universe, what your first
program that prints text should say. In a C# program, you enter a string
as a sequence of characters enclosed in double quotation marks. You’re
printing the text in Red. If you run this program, you get the display shown in Figure 5.
Although
it is perfectly okay to make your first program print something other
than "Hello World," I take no responsibility for any misfortune that you
suffer as a result of offending the programming gods in this way.
6. Changing the Font Properties
The program works all
right, but you really wanted something larger than this small text. It
is possible to scale text sprites, but at the moment it’s easiest to get
larger text simply by changing the XML in the SpriteFont
resource file. This also means that if anybody asks you what you were
doing today, you can say, "Oh, I hand-coded some XML," which should
impress them a bit. To get hold of the file that describes the font,
open it by double-clicking it in Solution Explorer for the BigClock project. Figure 5-6 shows which item to select.
The left window in XNA Game
Studio changes to show you the XML that describes the font to be
loaded. The font and the size of the text are set as shown here:
<!--
Modify this string to change the font that will be imported.
-->
<FontName>Kootenay</FontName>
<!--
Size is a float value, measured in points. Modify this value to change
the size of the font.
-->
<Size>14</Size>
You
can change the name of the font that you want to use and the size of
the font by adjusting the items shown in bold in this code. You can also
adjust the style and the spacing between letters. You can change FontName
to select any font installed on your computer (but personally, I really
like Kootenay). Use Control Panel on your Windows operating system to
find out what fonts are available. Make sure you type the name
correctly, including spaces and capital letters. You need to adjust the
font size depending on the font design that you select. I’ve found that a
font size of 100 gives nice large text using the Kootenay font on an
Xbox or a Windows PC screen. If you are using a Zune a size of 25 works
well.