Rob the Nest: Data persistence

With news from Brent that the AI simulation for our project is now complete, the only feature that remains to be implemented in Rob the Nest is data persistence. There exists a plethora of tools which offer this functionality in some form. The one I chose for this project was TinyXML2, a compact, efficient, and free XML parser library.

Several years ago I created a simple clone of the game Crimsonland, in which I had used a recent version of the original TinyXML library. Being unfamiliar with the new implementation, I embarked on a trek around the web, seeking out a reasonably complete TinyXML2 tutorial from which to extrapolate the code required for our project.

Unfortunately, there was very little information to be found, only a few incomplete guides with a handful of code snippets, and none of those provided examples of vital error checking. So, after getting down and dirty with the library myself, I wrote and posted a TinyXML2 tutorial for others to reference, which can be found here.

Needless to say, this part of the project went by without any major hitches. Additionally, I’m impressed with the redesigned interface offered by TinyXML2; It’s much cleaner and more intuitive to use than I remember the original TinyXML library being, and the experience provided me with an opportunity, however small, to give back to the community of developers who have provided so many other useful tutorials which I have referenced over the years.

Gotta be happy with that. 🙂

TinyXML2 Tutorial

Welcome to my TinyXML2 tutorial!

TinyXML2 is the second major iteration of a free, lightweight XML parser, commonly used for data serialisation across a range of platforms and originally created by Lee Thomason. This tutorial assumes that the reader already possesses the following:

  • An understanding of the fundamentals of C++ programming
  • Knowledge of the purpose of XML and the format & syntax of XML files

This tutorial is intended to demonstrate to the reader how to perform the following tasks using TinyXML2:

Overview of TinyXML2

TinyXML2 defines a number of classes which provide varying layers of required functionality. In this tutorial, these are the three classes of interest:

  • XMLDocument acts as a container for a collection of XMLElements, and is the primary interface for saving to and loading from XML files.
  • XMLElement is a container for a single XML element, including any attributes.
  • XMLNode is a base class of both XMLElement & XMLDocument, and provides the interface required for traversal of elements within a document.

Also of interest is an enumerated type defined in the library:

  • XMLError defines the possible success/error codes returned by many TinyXML2 functions.

The internal structure of an XMLDocument is organised as a tree of XMLElements, each of which is capable of containing its own children. Where these classes differ is that XMLElement is capable of holding data intended for serialisation, while XMLDocument is the interface for exporting to and importing from XML files. XMLNode is useful primarily because an XMLNode pointer can be used as an interchangable interface between an XMLDocument and its child XMLElements.

Getting started

The first order of business is importing the TinyXML2 library to your project. For this, you will need to download the source code, which is available from the TinyXML2 page on GitHub. Once you’ve done this, you can import it one of two ways:

  1. Directly add the two files tinyxml2.h and tinyxml2.cpp to your project, -or-
  2. Compile the source code into a .lib and link it via your IDE’s link manager.

Once you’ve done one of these, you will need to include the header in the appropriate file of your project. Note that the filepath declared in this line may differ, depending on where you placed tinyxml2.h and your project’s directory settings.

#include <TinyXML2/Include/tinyxml2.h>

Typically you will also want to specify a using directive for convenience, although it isn’t strictly necessary.

using namespace tinyxml2;

For my own convenience, I also defined a macro for checking error results:

#ifndef XMLCheckResult
	#define XMLCheckResult(a_eResult) if (a_eResult != XML_SUCCESS) { printf("Error: %i\n", a_eResult); return a_eResult; }
#endif

For readers who are unfamiliar with macros, this one is called just like a function, taking in the error result as an argument. If the result isn’t equal to XML_SUCCESS, it reports the error code to the console and causes the function it was called in to return that same error code.



Creating an XMLDocument

Creating a new document is ridiculously easy. It takes only one line of code:

XMLDocument xmlDoc;

By itself however, it is only an empty document. Writing this to a file will produce an empty XML file, so it can be used to clear expired data from an existing XML file, but for it to be truly useful it will need at least one child element.

It is a good practice to have a single root node within any XML document, which contains all elements within the document. It is also useful to retain a pointer to the root node as it makes it easier to add first-order child elements. Let’s create a Root node now, and store a pointer to it locally.

XMLNode * pRoot = xmlDoc.NewElement("Root");

This simply creates a new XMLElement named Root and associates the element with that XMLDocument. However, we must explicitly attach it to the XMLDocument.

xmlDoc.InsertFirstChild(pRoot);

With the Root node attached, we may now begin filling the document with data.



Putting data into an XMLDocument

In XML, data is stored within elements, generally one element per unit of data. Let’s create another element, which we will name IntValue.

XMLElement * pElement = xmlDoc.NewElement("IntValue");

XMLElement provides a number of overloaded functions for setting the value of an element. XML being based on text files, the name chosen for this function is SetText(), though the various overloads accept any primitive type to set the element’s value. In this case we will use it to set an int value.

pElement->SetText(10);

And then we add the new element as a child of the document’s root node.

pRoot->InsertEndChild(pElement);

Creating an element to store a float is practically identical, we simply have to make use of the float-argument overload of SetText().

pElement = xmlDoc.NewElement("FloatValue");
pElement->SetText(0.5f);

pRoot->InsertEndChild(pElement);

The other accepted primitive types are unsigned int, double, bool and const char *.

Setting an attribute:value pair within an XMLElement is just as easy. We simply use XMLElement‘s SetAttribute() function, specifying both the name of the attribute and its value. Naturally, SetAttribute() also has overloads for each of the primitive types accepted by SetValue().

pElement = xmlDoc.NewElement("Date");
pElement->SetAttribute("day", 26);
pElement->SetAttribute("month", "April");
pElement->SetAttribute("year", 2014);
pElement->SetAttribute("dateFormat", "26/04/2014");

pRoot->InsertEndChild(pElement);

It is often useful to nest XML elements within other elements in a tree structure, particularly when storing a group of related data. Let’s assume that we have a std::vector<int> containing an unknown quantity of values, each of which we want to store in its own element, and that we want to group this list of elements within the XML file. To do this, we first create a parent XMLElement which can be responsible for identifying its children as members of a list.

pElement = xmlDoc.NewElement("List");

We then iterate through the vector, creating a new XMLElement for each item and attaching it as a child of the List element.

for (const auto & item : vecList)
{
	XMLElement * pListElement = xmlDoc.NewElement("Item");
	pListElement->SetText(item);

	pElement->InsertEndChild(pListElement);
}

If we want to, we can also tell the List element how many members it has, though this is not strictly necessary.

pElement->SetAttribute("itemCount", vecGroup.size());

Don’t forget to attach the List element to the XMLDocument!

pRoot->InsertEndChild(pElement);

And that just about covers building the document data. Using different variations and combinations of these examples, it is possible to create complex XML files which store many different kinds of data. How you choose to structure these documents is ultimately up to personal preference – or possibly to your organisation’s coding standards, and TinyXML2 is robust enough that it can meet the data persistence needs of many small-to-medium sized projects.



Saving the XMLDocument to an XML file

Once the XMLDocument has been populated, it can be saved with a single function call. However, it is generally a good idea to check the returned XMLError code to ensure that the file was saved successfully.

XMLError eResult = xmlDoc.SaveFile("SavedData.xml");
XMLCheckResult(eResult);

Assuming that you have followed the examples listed in the previous section, your exported XML file should look very close to this:

<Root>
    <IntValue>10</IntValue>
    <FloatValue>0.5</FloatValue>
    <Date day="26" month="April" year="2014" dateFormat="26/04/2014"/>
    <List itemCount="8">
        <Item>1</Item>
        <Item>1</Item>
        <Item>2</Item>
        <Item>3</Item>
        <Item>5</Item>
        <Item>8</Item>
        <Item>13</Item>
        <Item>21</Item>
    </List>
</Root>

If it does, great! Because now we’re going to load up that file and pull the data back out again.



Loading an XML file into a new XMLDocument

TinyXML2 uses the same interface for loading XML files as it does for saving them. First though, we will need to create an empty XMLDocument in which to store the data in the file.

XMLDocument xmlDoc;

Then we simply load the file into the new document. It’s also important to confirm that the file loaded successfully, so we’ll store the result returned by LoadFile(),

XMLError eResult = xmlDoc.LoadFile("SavedData.xml");

..and check it using our macro.

XMLCheckResult(eResult);

We’ll be doing these checks frequently during the data extraction process, so from this point on they will appear in the examples wherever checking is required.



Extracting data from an XMLDocument

As with storing data into an XMLDocument, it is useful to obtain a pointer to the root node so that we can use it throughout the extraction process. We can do this with the following line of code:

XMLNode * pRoot = xmlDoc.FirstChild();

If for some reason no root element was found, FirstChild() will return nullptr. This generally happens when attempting to load a poorly constructed XML file, or a file that does not contain XML. In any case, if we have no root node we cannot continue, so we should abort loading and return an error code.

if (pRoot == nullptr) return XML_ERROR_FILE_READ_ERROR;

The next step is to find the element in which we stored our first piece of data, which we can do by searching for it by name. Note that this method only works if the node being searched has only one child element with the specified name, however there are other element traversal methods which we will examine later. For now, let’s find the element named IntValue.

XMLElement * pElement = pRoot->FirstChildElement("IntValue");
if (pElement == nullptr) return XML_ERROR_PARSING_ELEMENT;

Once we have the desired element, we can access the data inside it with one of several functions. In this case we expect it to contain an int, so we declare a variable of the appropriate type and pass it into QueryIntText().

int iOutInt;
eResult = pElement->QueryIntText(&iOutInt);
XMLCheckResult(eResult);

These functions will return a non-success error code if they are not able to convert the string within the element to the requested type, which is useful for checking data integrity, and has other applications which we won’t be looking at here.

Next we will extract the float we stored earlier, in much the same way.

pElement = pRoot->FirstChildElement("FloatValue");
if (pElement == nullptr) return XML_ERROR_PARSING_ELEMENT;

float fOutFloat;
eResult = pElement->QueryFloatText(&fOutFloat);
XMLCheckResult(eResult);

The next item we stored was an element named Date containing four attributes. We get this element as we would get any other element.

pElement = pRoot->FirstChildElement("Date");
if (pElement == nullptr) return XML_ERROR_PARSING_ELEMENT;

Extracting attribute data from an element is performed in the same way as extracting element data, except that we must also specify the name of the desired attribute.

int iOutDay, iOutYear;

eResult = pElement->QueryIntAttribute("day", &iOutDay);
XMLCheckResult(eResult);

eResult = pElement->QueryIntAttribute("year", &iOutYear);
XMLCheckResult(eResult);

Note that if the attribute’s value is a string no type conversion is necessary, so we can simply extract the attribute as raw text. However, because Attribute() returns null if no attribute with the specified name was found, and we cannot initialise a std::string with null, we must validate each result before proceeding.

const char * szAttributeText = nullptr;

szAttributeText = pElement->Attribute("month");
if (szAttributeText == nullptr) return XML_ERROR_PARSING_ATTRIBUTE;
std::string strOutMonth = szAttributeText;

szAttributeText = pElement->Attribute("dateFormat");
if (szAttributeText == nullptr) return XML_ERROR_PARSING_ATTRIBUTE;
std::string strOutFormat = szAttributeText;

The last child of the root node in our XML file is a list containing child elements representing individual list items. Let’s begin by getting the List element.

pElement = pRoot->FirstChildElement("List");
if (pElement == nullptr) return XML_ERROR_PARSING_ELEMENT;

Because the items in this list share the same name, we cannot use GetFirstChild() to iterate through all of them. We can however use it to get the first Item in the list, which we can then use as an iteration starting point.

Let’s create a new pointer to represent the list item we are currently traversing, and make it point to the first Item. While we’re here, we should also create a std::vector<int> for storing the values we extract.

XMLElement * pListElement = pElement->FirstChildElement("Item");
std::vector<int> vecList;

We now want to iterate through our list’s child elements and extract the value stored in each, until we reach the end of the list. The pointer we just set up makes this simple, as we can now simply use a while loop which terminates as soon as pListElement becomes invalid.

while (pListElement != nullptr)
{

For each item we encounter, we want to extract the int we previously stored in it and push that value into our std::vector.

	int iOutListValue;
	eResult = pListElement->QueryIntText(&iOutListValue);
	XMLCheckResult(eResult);

	vecList.push_back(iOutListValue);

We then want to iterate to the next element in the list before closing the loop, which we can do with this code:

	pListElement = pListElement->NextSiblingElement("Item");
}

By this point we have successfully extracted all of the data from our XML file. Observant readers will note that we have been potentially returning XML error codes throughout this function, and given that our XML file loading went without a hitch, it makes sense to report our success to the caller.

return XML_SUCCESS;

And that’s it!

Conclusion

In terms of its usability and simplicity, TinyXML2 is a vast improvement over its predecessor, and provides an interface which should be easy to use even for those who are still learning how to program.

Hopefully this tutorial has provided all the information you need to integrate TinyXML2 into your own projects. If it is missing some important feature offered by the TinyXML2 library, or you find any bugs in the code of these examples, leave a note in the comments and I’ll update it accordingly!

Rob the Nest: Adding fonts

Right from the beginning of this project, I wanted its presentation to be reminiscent of a professionally developed game. Naturally this required the inclusion of a system for displaying text to the screen, and I was very interested in implementing something which could make use of vector-curve based fonts such as TrueType font files.

For this feature I chose a third-party library named FreeType 2. This small and useful library provides a higher-level interface for loading and rendering the glyphs defined by a TrueType font into a texture, however it does require the user to implement additional functionality to determine where those textures are rendered in the window, as well as providing any desired text formatting.

I used leads from a variety of resources while putting this part of the project together. One in particular was quite helpful, however I seem to have misplaced the link, so unfortunately I cannot post it here yet. Regardless, the FontModule class I created turned out to be about half as effective as I had originally intended it to be, and is plagued by a number of issues which for now I am unsure how to fix. The most noticable, and in my opinion most game-breaking bug occurs upon resizing the window, causing both misplacement & dimensional skewing of all fonts displayed on the screen.

In short, I am unsatisfied with my implementation of this module. It does the job well in our default resolution however, and due to time constraints we’re going to leave it as it is. At some point I will take the time to revisit and redesign it into a generalised font rendering module which can be imported into other projects.

Onward to the final leg of the project: data persistence!

Rob the Nest: Graphical User Interface

Earlier this year I started developing a small personal project. The main purpose of this project was to demonstrate 3D view frustum render culling, and one of the subsystems I created for this project is a parentable 3D node which could be used to construct complex scenegraphs.

How is this relevant to the implementation of a GUI in an entirely different project? Upon examination of the problem space, it was immediately clear that a similar design pattern could be used to build and effectively manage 2D scenegraphs. A family of classes could then be derived from the 2D node to introduce the functionality for an interactive GUI.

Parentable 2D node

Internally, the Node2D class is rather simple. Its key function is scenegraph transform parenting, handled through the use of a member 3×3 matrix and several access & set functions for pertinent data in both local and global space. It also provides functionality for depth-first hierarchical update & draw routines, to simplify updating and rendering of its scenegraph.

The UIElement class family

Derived from Node2D, UIElement provides several important features for presenting interactive GUI elements:

  • enum ETextureHandle {} defines IDs for every texture loaded for all UIElements, each of which is used as a key for storing texture handles in a static member std::map. The purpose of this is to allow centralised management of all textures through static Init() & Destruct() functions, and to allow multiple elements of different types to share textures when appropriate.
  • static DrawTexture(ETextureHandle a_eTexture, const glm::mat3 & a_mTransform, const glm::vec2 & a_vExtents, float a_fAplha) utilises a statically-scoped, mutable vertex buffer to render the specified element texture. I chose this method of drawing element textures primarily to prevent code duplication.
  • typedef void (*OnActionCB)(UIElement * a_pButton, void * a_pUserData) typedefs a callback which is set at initialisation of each element, for processing upon user interaction with that element.

Built upon this foundation are a number of element types, each with its own specific functionality:

  • UIButton is a simple click-type button, which processes its callback when a user presses and releases the mouse button while the cursor is over that element.
  • UICheckbox contains a boolean state which is updated whenever the user simply clicks on it.
  • UIRadio contains an integer-type state, and hosts a std::vector of UICheckboxes, only one of which can be checked at any one time.
  • UISlider contains a member float with a range limited to a value between 0 and 1, inclusive. This allows the value to be used as the interpolation point between externally-stored minimum and maximum values, meaning that UISlider can remain ignorant of the proper range of values required by external accessors.

Here is a screenshot of the GUI in its final state. Note that the ‘Start simulation’ button is highlighted because my cursor was hovering over it when I took the screenshot:

Rob the Nest - Options screen
Rob the Nest – Options window screenshot

Obligatory credits:

  • The font displayed in this screenshot is the ‘Space Ranger’ TrueType font, free for personal use and available here.
  • The ‘Dark Hex Grid’ used for the background is also free for personal use, and the original version may be found here.
  • The textures used for the elements are authentic programmer art, created in Paint.net by yours truly.

Structurally, the scene in the screenshot is comprised of two major branches: The first contains three buttons for switching to other screens, and the second contains the radios & sliders for changing settings, as well as blank panels for displaying effective values set by sliders. The elements of each branch are parented to the respective branch node, and both of these branch nodes are parented to the scenegraph root node, positioned at the center of the window.

Next I will discuss adding fonts to the GUI!

Rob the Nest: Program state management

The first task to tackle for Rob the Nest was to create a system for managing changes to the program’s state. A few specific features stood out as being of particular importance:

  1. Seamless transition between different screens/scenes
  2. Complete separation of update and draw routines
  3. Updating by a fixed timestep
  4. Variable draw frequency with an upper-bound frame rate limit
  5. Dynamic draw cycle skipping for slower-running host machines
  6. Minimal external code required to initiate changes to the program state
  7. Centralised management of all of the above features

This seemed a task for which polymorphism was designed. Intuitively, the functionality for each screen could be contained within a single object with its own update and draw processes, its own GUI, and some basic information about its possible exit states. All of these objects could then share a generic, higher level interface which required little information about the internal state or function of each object.

The AppState class

The requirements listed above are met primarily by three public static functions defined within this class:

  • PushState(AppState * a_poState) pushes the specified state onto an internal stack, allowing external objects to initiate transitions to new active states. This meets criterion 6, and supplements Update()‘s functionality to meet criteria 1 & 7.
  • Update(float a_fDeltaTime) takes in deltatime and updates an internal time counter, then compares that counter to an internally stored fixed update timestep to determine the number of updates which need to be performed. It then performs those updates on the currently active state, processing any new state transitions immediately after each update. This collection of functionality meets criteria 2, 3 & 5, and is primarily responsible for meeting criteria 1 & 7.
  • Draw() checks the time passed since the previous draw call and aborts when it detects calls more frequent than an internally stored fixed draw timestep. When rendering is required, it processes sequenced rendering of all states on the internal stack, ending with the active state. This allows the active state to be superimposed upon other states lower in the stack, such as in a pause overlay. This function meets criteria 2 & 4, and supplements the two functions above to meet criterion 7.

Also declared in this class are four protected-access virtual functions which child classes must provide definitions for, and which will be examined later.

Using the AppState class

Being a base class with a protected constructor, AppState can not be directly instantiated. Instead, external objects interface directly with its static functions to perform updates, render states, and initiate state transitions. To ensure that this can take place, a few additional static helper functions have been implemented.

The first task is to initialise any static data required for the class. This is done by placing the following line in the constructor or initialisation function prior to the run loop in the program’s call to main().

AppState::Init();

Next, a new state must be placed onto AppState‘s internal stack for processing. This requires that at least one child class has been declared, and for the purpose of this demonstration let’s assume that there exists such a class, named SplashState. Pushing the splash state onto the stack is done with this code:

AppState::PushState(new SplashState());

It is allowed to push more than one state onto the stack at a time, the last becoming the topmost, and therefore the active state. However, note that if the topmost state pushes a new state onto the stack when it exits, any states underneath it will remain inactive on the stack, as the new state becomes the topmost, thus the active state.

AppState::PushState(new MenuState());       // Main menu
AppState::PushState(new SplashState2());    // Second splash screen
AppState::PushState(new SplashState1());    // First splash screen

This is useful because states can declare no exit state, and will then by default exit to the state below when stacked on top of other states. Once the desired states have been pushed onto the stack, it is as trivial to update active states,

AppState::Update(fDeltaTime);

..as it is to draw them.

AppState::Draw();

Finally, at program closure it is necessary to free up any resources allocated to the AppState class, and ensure that there are no states remaining on the internal stack.

AppState::Destruct();

Individual states

As discussed above, each individual state is an instance of a class derived from AppState, which must provide definitions for four virtual functions declared in the parent class.

  • OnInsert() is executed when the state is placed onto the stack, and may be regarded as an initialisation function.
  • OnUpdate(float a_fUpdateTick) updates the state.
  • OnDraw() renders the state.
  • OnRemove() is executed when the state is removed from the stack, and serves as a destruct function.

Each of these classes is responsible for managing & updating its own resources, rendering its scene, and pushing its exit states onto the AppState stack. Additionally, the stack is capable of containing multiple instances of a state without causing data conflicts, providing that the functionality of each state is self-contained.

Conclusion

This state management system took nearly a week to concept, develop and debug. Given that my primary task is to implement a GUI, at first I was concerned that I was spending too much time on this part of the program. The final result banished these concerns however, as it allows me to encapsulate and focus on a single scene at a time, without having to worry about cross-scene conflicts or data contamination. While it certainly isn’t perfect, it does provide a solid foundation on which to build the rest of the project, and in retrospect I consider that week to be a worthwhile investment.

For those interested in viewing the source code for this class, I have posted a stripped and fully commented version to pastebin.

Next up, the GUI!

Rob the Nest: Conception

This week marks the beginning of a new assignment cycle at college. We have been tasked to produce a functioning project which demonstrates one of three possible features: Procedural generation, an AI simulation, or a complex user interface. We have also been offered the option of working in a team of two programmers, so long as each programmer chooses a different feature for their part of the project.

Having previously produced a lean C++ library implementing dynamic and expandable Behaviour Tree AI in a previous project, I have opted to challenge myself by tackling the GUI feature – something I have little experience with so far. One of the other students, Brent McEwan has agreed to team up with me on this project, and will be creating an AI simulation based on a schoolyard game known as Rob the Nest.

For the moment we are still discussing preliminary design patterns, and plan to put together a broad structure of the project over the coming weekend. More to follow!

Dev.blog  #1/1  Implemented development blog

Hello, and welcome to my devblog!

I am Shiloh James, and among my many and varied interests is a passion for video game development. At the time of this writing, I am in the process of completing 2nd year studies at the Academy of Interactive Entertainment‘s Sydney campus, where I am undertaking the Advanced diploma of Professional Game Development, specialising in game programming. And I’m having a simply ridiculous amount of fun in the process.

The purpose of this blog is to provide a place for me to discuss some of the challenges presented by the projects I have worked on, showcase a portfolio of my work, and reflect upon my experiences with software development in general. I’ll also post guides and tutorials from time to time, either because I was unable to find one which adequately covers the topic, or because I feel it demonstrates a concept or implementation which is neat or novel enough to justify sharing it with the wider developer community.

Dialogue is welcomed, as well as constructive criticism. If you have any questions on the topic addressed in a post or suggestions for improvement, I invite you to reply in the comments, with one caveat: Please try to be respectful of other participants.

With that out of the way, let’s move on with the fun!