Ok so here’s my first tutorial! I thought I’d go with something light to ease you into it, hope you find it useful…
So this tutorial focuses on retrieving data for your C#/XNA application from an XML data file. The idea is so that data elements can be parsed and read into your application sequentially (as opposed to serialising the entire xml document into an equivalent binary construct) . This can be especially useful for a number of reasons; if you have a large amount of data of the same type that you wish to store in a single file (a list of bitmap font data descriptions for instance) then you can simply read each element of the data one-by-one and do something with it (sotre in an internal/external structure, process it and move onto the next etc..) This is much simpler than having to create a seperate xml file for each description and serialising each one which could become painstakingly tedious..
The key to this tutorial is a little class called the XmlReader ( can be found in System.Xml). Using this class is pretty simple and straight forward and you only have to make sure you know the specific tags your interested in within the file to make it work for you.
Now let’s get down to business…
Let’s say we have a folder containing a load if bitmap fonts each labelled “BmpFontOne.tga”, “BmpFontTwo.tga” etc… Now let’s say we want to load some of these fonts into our XNA game but we need a means to specify exactly which ones the game should load and in what order..
Lets say we have an .xml file which looks like this:
<?xml version=”1.0″ encoding=”utf-8″ ?>
<FontManager>
<numFonts>8</numFonts>
<FontObj> <fontType>0</fontType> <fontName>BmpFontDefault</fontName> </FontObj>
<FontObj> <fontType>0</fontType> <fontName>BmpFontBankGothicB18</fontName> </FontObj>
<FontObj> <fontType>0</fontType> <fontName>BmpFontEarthR16</fontName> </FontObj>
<FontObj> <fontType>0</fontType> <fontName>BmpFontEddieR20</fontName> </FontObj>
<FontObj> <fontType>0</fontType> <fontName>BmpFontEurostarR20</fontName> </FontObj>
<FontObj> <fontType>0</fontType> <fontName>BmpFontGriffonShadowR20</fontName> </FontObj>
<FontObj> <fontType>0</fontType> <fontName>BmpFontGunmetalR20</fontName> </FontObj>
<FontObj> <fontType>0</fontType> <fontName>BmpFontTech001</fontName> </FontObj>
</FontManager>
Now as we can see the file contains a description of each bitmap font we want to load which is made up of a fontType (to tell the game whether it’s a truetype font or a bitmapFont, not used for this particular example) and a fontName (used to load the desired file). Notice we don’t specify an extension for each fontName (e.g. .tga) because we assume the bitmapFonts have been imported into game project and setup to be pre-processed using the framework content pipeline (in this case using the custom bitmapFont processor defined in MS’s FontSample example (See Samples)..
Now in code I setup a class called FontManager which has a couple of interesting tidbits in it. FontManager contains a smal class called FontObj which defines a font and contains a few attributes; a fontType, a fontName and the Font object (defined elsewhere) to be created once the fontName and fontType have been defined. Also FontManager contains a List object which we will use to store theFontObjs once we know how many to add.
In the FontManager’s LoadFonts() method we do the following:
public void LoadFonts(ContentManager content)
{
// Read setup information from the xml file..
Stream stream = File.OpenRead(kFontPath + kFontFileName);
ReadXMLFile(kFontPath + kFontFileName);
// Load each font using it’s own xml-read data..
for(int idx = 0; idx < numFonts; idx++)
{
m_fontObjectList[idx].m_font = content.Load<Font>(kFontPath + m_fontObjectList[idx].fontName);
}
}
private void ReadXMLFile(string filename)
{
//load the xml file into the XmlTextReader object.
XmlTextReader XmlRdr = new System.Xml.XmlTextReader(filename);
//while moving through the xml document.
int typeIterator = 0;
int nameIterator = 0;
bool ListIsReady = false;
while (XmlRdr.Read())
{
//check the node type and look for the elements desired.
if (XmlRdr.NodeType == XmlNodeType.Element && XmlRdr.Name == “numFonts”)
{
numFonts = XmlRdr.ReadElementContentAsInt();
// Now we have the number of fonts to read we need to fill the fontlist
// so we can read in the font data.
for (int idx = 0; idx < numFonts; idx++)
{
m_fontObjectList.Add(new FontObj());
}
ListIsReady = true; // guard to make sure we have font objects to fill with data..
}
if (ListIsReady)
{
//check the node type and look for the elements desired.
if (XmlRdr.NodeType == XmlNodeType.Element && XmlRdr.Name == “fontType”)
{
m_fontObjectList[typeIterator].fontType = (fType)XmlRdr.ReadElementContentAsInt();
typeIterator++;
}
//check the node type and look for the elements desired.
if (XmlRdr.NodeType == XmlNodeType.Element && XmlRdr.Name == “fontName”)
{
m_fontObjectList[nameIterator].fontName = XmlRdr.ReadElementContentAsString();
nameIterator++;
}
}
} //endwhile
}
Notice that in LoadFonts() we call the method ReadXMLFile() which handles all the .xml parsing, before we proceed to load in all of the specified fonts. Also we can see that in ReadXMLFile() we start by opening up the file stream to read from the file before parsing the first data element. The initial element, which defines the number of fonts to be loaded, is taken and processed by using it to create FontObjs and adding them to the List structure. Once all the FontObjs have been created we then proceed to continue parsing the file to retrieve the data descriptions of the specified number of fonts.
Lastly we use the content manager to load all of our brand spanking new fonts into the game for use..
This system is considerably flexible as it allows you to change and alter the number of fonts you wish to use in your game without recompilation. You wanna add a new font? just up the font number in the .xml doc and add a description for it! Also if you really wanted to get fancy you could have seperate .xml files each named differently (MenuFonts.xml, WorldOneFonts.xml, MiniGameFonts.xml etc..) and load in each one for a specific subsystem in your game. That way each subsystem can have its own description of the fonts its going to use, which the descriptions pointing the content manager to the files to load (which could be kept in a global font pool/folder)..
Also it isn’t just useful for fonts as you can use a variatino of this system to load in variable quantities of description/data sets for just about anything you can think of..
Lastly I just want to note that I also included into FontManager two methods named GetFont(), one which takes in an index parameter and returns the FontObj in the List at that particular index, and the other method which taking in a string defining the font name and returns the FontObj which owns it (a little slower due to the string comparision)..
Well that’s it for my first tutorial but check back soon for some more in depth, XNA/game centric offerings as and when time permits..
Also if you have any requests for tutorials then you can drop me comment and i’ll try and fit them into my schedule wherever possible..
- Hog
March 23, 2008 at 5:52 pm
This way of “reading” XML isn’t any better than reading a text file with one font per line. The structure of XML is totally unimportant in the case you’re suggesting here, which means that you might have problems in your XML document and not even realize it.
That being said, if it solves a problem, then it probably has a use.
August 14, 2008 at 11:10 am
can u plzz change the font color to normal than
showing ur creative ness
September 29, 2008 at 2:46 am
Thanks for the tutorial!
March 26, 2009 at 11:26 pm
Actually this tutorial was very helpful for me.
I was looking for hours for an appropriate example.
After checking this tutorial the third time, I realized that’s exactly what I needed.
So… thank you very much!
I’m so glad I finally can continue my project
June 4, 2009 at 2:55 am
Sweet blog. I never know what I am going to come across next. I think you should do more posting as you have some pretty intelligent stuff to say.
I’ll be watching you .
June 21, 2009 at 9:13 am
Been looking for a while now how to load level-data into my game. Your example uses ‘Stream’ and ‘File.open’ which are unkown when I add them to my game. Are these instanced of your own classes or are they part of the Framework? What classes to import in that case?
Tnkx, Justin
June 22, 2009 at 6:12 am
There part of the .Net framework libraries. Either Google them or check MSDN to find out where they live and which packages you need to include in your source file in order to use them..
Hope that helps!