Saturday, 24 December 2011

Load in Place data structures and Pointer Fixups

PROLOGUE:

When I first started this blog post my intention was to describe the process of loading full game assets using the Load in Place technique in C++, I quickly realised however that I probably needed a little more context before jumping into a full example so what you're reading now is the result.

Please bear in mind all of this is done purely as an example to learn the core concepts, you would never use this in a real project. You would ideally want some nice way of encapsulating what is happening by providing friendly interfaces to handle loading for you, but I find these interfaces can often obscure what is actually happening when you are first learning this stuff, to I have omitted this for clarity. I will hopefully at some point in the future provide an example of such an interface to use all this code with! (We also would want a generic implementation capable of loading lots of different types of files and also the ability to load more than one object at once, but we'll worry about that stuff later).

THE BEGINNING:

Simple File I/O in C:

I decided to use the file I/O in C for this example as opposed to C++. There are some differences and in retrospect C++ maybe have been a better call but they achieve pretty much the same ends. I am sure if you're that way inclined you could port these examples to use fstream instead and I may well revisit this in future to do just that.

Here is a simple example of saving a file with some data you have created:
(I suggest having a read through this article if you are not too familiar with File I/O in C:
http://www.cplusplus.com/doc/tutorial/files/ )

class Foo {
public:
    int i;
    int j;
};

int main(int argc, char** argv)

{
    FILE* file;
    file = fopen("MyFile.bin", "wb");

    Foo myFoo;
    myFoo.i = 1;
    myFoo.j = 2;

    fwrite(&myFoo, sizeof(Foo), 1, file);
    fclose(lfile);

    return 0;
}

So what's going on here. First we create a file in the local directory called "MyFile.bin". The extension is used to identify the file as being in binary format, when we create the file we open it for writing in binary mode which is what the "wb" represents - 'writing,binary'. We then fill in a very simple structure and write that structure to disk, making sure to close the file after. We have just saved the state of our object, which is pretty neat. Imagine if that was the score in a given level or the amount of health we had left at a particular save. The cool thing is getting that information back is super easy as well! All we need to do is this:

class Foo {
public:
    int i;
    int j;
};

int main(int argc, char** argv)
{
    FILE* file;
    file = fopen("MyFile.bin", "rb");

    Foo myLoadedFoo;

    fread(&myLoadedFoo, sizeof(Foo), 1, file);
    fclose(lfile);

    cout << "i: " << myFoo.i << "j: " << myFoo.j << endl;
    return 0;
}

To get the data back we just read the file and fill in a blank struct of the type we saved. We open the file for reading in binary mode "rb - reading,binary", call fread instead of fwrite and fill in our struct. If we print out the contents you will find we have the output of 1 and 2 on screen. Pretty cool right?

THE MIDDLE:

Where things get interesting is when we have pointers in those objects to some data else where in memory. How do we store that dependency? If we were to use the method above with a pointer in Foo, like this:

class Foo {
public:
    int   i;
    int   j;
    char* p;
};

The method we just discussed will unfortunately not work, lets see why. Take a look at this next example.

class MessageList {
public:
    char hello[6];
    char goodbye[8];
    char cheese[7];
};

int main(int argc, char** argv)
{
    // This is just an example of a standard resource 
    // load you can think of happening in a resource manager
    // This would probably also be loaded from a file at some 
    // earlier stage in the program in a real world situation.
    MessageList myMessageList;

    char* hello =   "Hello";
    char* goodbye = "Goodbye";
    char* cheese =  "Cheese";
    
    strcpy(myMessageList.hello,   hello); 
    strcpy(myMessageList.goodbye, goodbye);
    strcpy(myMessageList.cheese,  cheese); 
    // End of file load  

    FILE* file;
    file = fopen("MyFile.bin", "wb");

    Foo myFoo;
    myFoo.i = 1;
    myFoo.j = 2;
    myFoo.p = myMessageList.cheese; 

    fwrite(&myFoo, sizeof(Foo), 1, file);
    fclose(lfile);
    return 0;
}

Now there is a little bit more going on here but most of it isn't really that important, it's just to set up the example so don't worry too much about it if you don't get it all. Basically think of MessageList as a memory pool, which might easily contain all kinds of game assets like textures and models and sounds. I just set up some default strings and copy their value across into the structure in the same way I would load a texture and then store it in a block of memory somewhere. The way you load and store these assets is up to you, you can store them dynamically or allocate them statically, just make sure the object you're saving (in this case Foo) has access to that memory chunk. So going back to the example, I save the memory address of myMessageList.cheese and then write the myFoo object to disk.

The problem with doing only this is that we cannot guarantee MessageList will be at the same address in memory when we try to load it as when we saved it previously (in fact it is pretty much guaranteed this won't be the case). There is no way of going between the address it resided at when you saved it and the address you actually want when you come to load the object, so that just won't work. What we need is a way of translating our pointer from it's old address to the new address of MessageList when it is loaded. When we save Foo, if we know the start address of MessageList when we save it, and the address of what the pointer in our object is pointing to in MessageList, we can calculate the offset of that pointer by subtracting one from another!

class Foo {
public:
    int   i;
    int   j;
    char* p;
    uintptr_t offsetOfPointer;
};

class MessageList {
public:
    char hello[6];
    char goodbye[8];
    char cheese[7];
};

int main(int argc, char** argv)

    MessageList myMessageList;

    char* hello   = "Hello";
    char* goodbye = "Goodbye";
    char* cheese  = "Cheese";
    
    strcpy(myMessageList.hello,   hello); 
    strcpy(myMessageList.goodbye, goodbye);
    strcpy(myMessageList.cheese,  cheese);      

    FILE* file;
    file = fopen("MyFile.bin", "wb");

    Foo myFoo;
    myFoo.i = 1;
    myFoo.j = 2;
    myFoo.p = myMessageList.cheese; 

    // Here we store the offset of the pointer, this should 
    // really be stored in a pointer lookup table and not as 
    // part of the object but I have left it here for simplicity.
    myFoo.offsetOfPointer = (uintptr_t)myFoo.p - (uintptr_t)&myMessageList;

    fwrite(&myFoo, sizeof(Foo), 1, file);
    fclose(lfile);
    return 0;
}

The line

myFoo.offsetOfPointer = (uintptr_t)&myFoo.p - (uintptr_t)&myFoo;

might look a bit confusing but it really isn't. uintptr_t is just a typedef of an unsigned integer value and it is only used to guarantee cross platform compatibility. It provides a large bound for the size of the number it can store as well, (in this case we could probably just use 'long' and it would still work on most platforms). We cast the memory address to integers, and because the object is contiguous in memory, subtracting one address from the other gives us a value of how far the pointer in bytes is into the data structure. So all we need to do is save the offset of the pointer, not the pointer itself, and use that offset to 'Fix-up' the pointer when we load the object again. Ideally you store the pointer offsets in another file which is not part the object you're interested in, you'd then load them at the same time and use the offsets stored in your pointer lookup table,  I have just stuck the offset in the object for brevity.

THE PAYOFF:

Right, so we have saved our object and the offset of the pointer into the memory pool we are loading from (in this case MessageList). Lets see how we actually do the pointer fix-up.

class Foo {
public:
    int i;
    int j;
    char* p;
    uintptr_t offsetOfPointer;
};

class MessageList {
public:
    char hello[6];
    char goodbye[8];
    char cheese[7];
};

int main(int argc, char** argv)
{
    MessageList myMessageList;

    char* hello   = "Hello";
    char* goodbye = "Goodbye";
    char* cheese  = "Cheese";

    strcpy(myMessageList.hello,   hello);
    strcpy(myMessageList.goodbye, goodbye);
    strcpy(myMessageList.cheese,  cheese);

    FILE* file;
    file = fopen("MyFile.bin", "rb");

    Foo myFoo;
    fread(&myFoo, sizeof(Foo), 1, file);

    // Here we cast MessageList to be an array of chars 

    // in order to make sure when we use the offset to do 
    // some pointer arithmetic, we are adding only
    // 1 byte (char == 1 byte) per offset so we move the correct 

    // distance into the data structure for our pointer offset.
    char* data = (char*)&myMessageList + myFoo.offsetOfPointer;

    // We then cast the data back to the same type of the pointer. 

    // In this case we actually stored a char* pointer so the next
    // step is a bit pointless, but imagine it was another user
    // defined type such as Model, you would just do
    // myFoo.model = (Model*)data;
    myFoo.p = (char*)data;

    fclose(lfile);
    return 0;
}


The lines you want to pay attention to are these ones:

char* data = (char*)&myMessageList + myFoo.offsetOfPointer;
myFoo.p = (char*)data;


What we are doing is casting the MessageList to be an array of chars, this just means we can treat the structure as a chunk of bytes in memory that we can index into. When we calculated the offset before, that gave us the offset in bytes, so by adding the offset to the start address of MessageList after we have cast it to an array of chars will leave us at the correct place in memory where we want to fix-up our pointer! The second line in this case is actually redundant as it happens we are dealing with char arrays anyway with our string values, we don't need to cast the char* back to the object type of our pointer because it's already a char*, but what if our pointer was to another user or fundamental type such as Model or int, we would need to cast it back to the correct type before we could use it.

And that is pretty much it! Once you have done that you have completely loaded your object and can do with it what you please. I must stress that this really is the simplest example of Load in Place, and hopefully now you can see the power and potential of such a technique. As I said before, creating a lovely interface to handle all this nitty gritty stuff for you is absolutely the way to go, and I will try and dream up something as an example in not too long.

I hope this has been of use to you and made pointers and loading data not quite so scary as it may have been before. (Also if I have got something wildly wrong please let me know!)


Tom out.

(Also check out these articles on Load In Place which go into much more detail and are great resources which helped me)

http://entland.homelinux.com/blog/2007/02/21/fast-file-loading-ii-load-in-place/
http://www.gamasutra.com/view/feature/3984/delicious_data_baking.php?print=1

Thursday, 9 September 2010

Angry Robot Rampage is OUT!

Angry Robot Rampage has been released on Xbox Live Marketplace!

The feeling is quite surreal that something I have made is now being played across the world (well I hope it is anyway)

If you have been so kind as to download and play my game, I am eternally grateful to you and would love nothing more than to give you an enormous hug and/or high five. I really hope you enjoy playing it and that it puts a smile on your face.

Here is a fan page if you are interested in spreading the love - http://www.facebook.com/pages/Angry-Robot-Rampage/112880442102923?v=page_getting_started

You are welcome to follow me on Twitter as well at http://twitter.com/pr0g89

Thank you so much for your time and interest, I appreciate it more than you'll ever know.

Warm regards

Tom out.

Monday, 6 September 2010

Angry Robot Rampage

Hello Internet(z)

It has again been a long while since I have written anything here and to those of you who care (if there are indeed any of you out there) I apologize inexorably. On a positive note however, I have actually been working on something that might be worth writing about.

Over the past two months I have been working on a game for Xbox Live Indie Games, and it is now on the verge of release - This is my story.

In the beginning, I knew whatever I was going to work on would need to be small - I had to be able to complete it over the summer. That meant no sweeping story-arcs, no endless levels escalating into ever higher and obscure difficulties, and no torrents of exposition about the characters motivation and inner most feelings -(not that there's anything wrong with these things - but I knew I didn't stand a chance of pulling off such a game). I needed something with a small enough scope so that it could be reasonably polished, fun to play, and artistically appealing.

In mulling over ideas for the game, one idea kept coming back up, and that was SHOOTER. I had recently played a fantastic game for the iPhone called 'Zombieville: USA' (I highly recommend checking it out if you have an iPhone) You play an intrepid adventurer batting through hordes of zombies while slowly leveling up and gaining new weapons, it has some really nice design, and a wonderful art style. I wanted to create something like this then, but what, and how?

Work began very slowly. The first thing I knew I needed was a protagonist, but how to create such a chap.
I began by creating a little man through the use of a sprite sheet (where I would draw each individual frame of him running) but this soon proved to be far more arduous and time consuming than I had first anticipated. (I can draw, but an artist I am not - My respect for animators and people who do this full time has increased exponentially - especially the artists who worked on the XBLA game 'Shank'). To remedy my inadequacies in the art department, it was decided that the protagonist could be updated and animated (though somewhat crudely) through the wonders of computer code. The hero was born.

I had a man on screen, bobbing up and down in front of the CornFlowerBlue background that all XNA coders will be familiar with, but then I realized - 'What the 'heck' do I do next!?'

This stage of development is probably one of the worst (perhaps just behind bug fixing). You know what you want, but as with anything in programming, there are about five million different ways of going about it. To get me moving again, I went in search of inspiration. I am eternally grateful to the example code and tutorials at creators.xna.com. I dug through many of them, looking at techniques and examples to give me a better understanding of what I should be doing, and how I should be doing it. In particular I would like to make mention of the GameStateManagement and SafeAreaBounds examples. They helped me a lot in the beginning in getting my game structure working as well as the lovely scrolling background.

A few weeks later and things were slowly starting to take shape. I had a robot who would follow you round, a scrolling background, different states to handle my game, and.... well that was about it. At this stage I had what you call programmer art. (Please see below)


It was time to step up the time I was working on the game and start making stuff look cool! I contacted an old friend of mine named Richard Dorran, a fantastic artist and video game compatriot. I realized if the game was going to look any good at all I was going to need some lovely background art (largely to distract from the mediocre game play). Richard happily agreed, and it was then that the game went from 'lame prototype' to 'OMFG, this looks like a real game!'

Many discussions ensued ranging from the number of enemies to the color of my protagonist bandanna. Slowly things started to take shape, and within a few weeks, we had something that looked like this.


It was looking better, but the game play was pretty dreary (far more than it is now believe you me). It was over this part of development where programming is the most fun. You have the basic structure in place, and adding features doesn't seem as painful as before. You can experiment a lot, and see what works, and more importantly, what doesn't. It was in this phase that grenades were added, as were the red patches on the enemies back to cause them to blow up in one shot, and finally a flying enemy to make the enemies ever slightly more varied.

Before you could tip your hat to the attractive passer by, we were nearing completion. At this stage focus was moved to the sounds and menus and all other manner of things not related to the game itself (which all add up to be a lot more than you think). Another good friend of mine, one Ed Trethowan provided some lovely background music while SoundSnap.com provided the screams and dulcet tones of my hero that grace your ears. It was here too that I realized we needed a developer name, and ToRchEd was born (See if you can guess why that was the name)




The last and final hurdle was the addition of a high scores table. This was one the most painful programming problems I have ever experienced. The save and load operations required for a high scores table worked perfectly on the computer, but as soon as you tried to run it on the 360.... BOOOOOM - Error Code 4, thank you, try again. You of course cannot debug your code while it is running on the 360, so good luck finding out exactly what went wrong. I was stumped for a while on this but finally managed to crack it (I will upload how I did it soon if anyone is interested)

Now came the scariest part of all - submission. Up until this point it had only been me, my family and a few close friends who had laid eyes on the game, seeing it slowly take shape over the weeks and moths I had been working on it. Their comments were always positive and encouraging, but what happens when you throw it out to the internet.. What if they hate it? What if all of this has been for nothing!?
Luckily things went smoother than I had thought, the community at creators.xna.com are very friendly, and they were constructive and helpful in their criticism. It is thanks to them that multiple weapons were added as well as a slightly higher jump, and a slew of other small fixes.

So here ladies and gentlemen, is the finished article.


As I sit here typing the game is in the process of peer review and should be out within a week or so. It has been a roller coaster ride, with ups and downs, and thrills and chills. It has been a fantastic experience, and I cannot wait for the rest of you adorable people out there to be able to play it!

I'll post here again when the game is available for public consumption.

Thanks for reading,

Peace and love,

Tom out.

(P.S. Here is a link to a video of the game! http://www.youtube.com/watch?v=ix31gnNFgJU Enjoy :) )

Wednesday, 12 May 2010

Tower Defence is Finished!

Hello!


Jeez it has been a while since I have written anything here. I apologise if you've been holding your breath. If you have that's incredible! and If not I hardly blame you.


Well my Final Year Project is done, finished, finito. The hand in for not only the code but the 15,000 word dissertation was the 6th of May. In the week since I have been primarily breathing sigh after sigh of relief that it actually turned out okay. Below is a screen from the end result.






It wasn't perfect, there were bugs, there were things that I'd have done differently, things I wish I could change, but considering it was the first 'large' piece of software I have ever written, and definitely the one I have spent the most time on, it certainly could have been worse.


The experience was a roller coaster ride of emotions; Joy, despair, love, hate, pride and disappointment. There were times of pure ecstasy when features would come to life, and moments of sorrow and anger when things just didn't work. At times the code would seem majestic and beautiful, at others it would look like a hacky mess.

I have learnt so much from the experience. My knowledge of design, construction, debugging, and test has increased dramatically, but I feel the most important lesson I have learnt is the notion of compromise. Being realistic in your aims and what you hope to achieve is so very important to make sure you get something at the end. Now I'm not saying don't be ambitious, please set your sights high, but you have to realise you're not going to create a Call of Duty killer in the space of 6 months as an undergrad comp-sci student.

Now what I want more than anything is to take everything I've learnt and apply it to something new, something better, something even cooler!

I will endeavour to update more often here and keep up the witty prose.

Thank you for your time old chum,

Tom out.

Thursday, 4 March 2010

Height Maps

Greetings and salutations my friends, I hope you're well! I am in a specially good mood today as I have recently implemented a new feature in my game, and it actually looks cool!

Over the last few days I have been working on a cool way of creating a background for my tower defence game. When speaking with my project supervisor Simon, he mentioned it might be a good idea to create a height map which can be used to render a terrain.

First off, a height map is a way of procedurally generating a graphical scene. The height map itself is basically a grey-scale image (think of clouds) which acts as data that you want your program to get hold of. In order to get hold of the data, you go through the image, taking each pixel in turn, finding the intensity (level of white/black) in each one. The values of each pixel correspond to the heights of your vertices when you go to draw your scene. So white would be the highest point, and black would be the lowest, with all the greys somewhere in between. As you draw your vertices, you go through the list of pixel data and set the height to the corresponding value (you can of course scale this afterwards if you want).

This all sounds perfectly simple and straightforward, and I guess it is compared to some problems you'll face, but as I have come to learn, things are never as simple as they first seem. The first problem I had was getting hold of the actual pixel information itself. I am using SDL to load my images, and while the SDL_Surface object is great, it is not at first blindingly obvious how to get hold of each pixel. Realising I wasn't going to get that working first, I decided to get the drawing code working, and then work out what the height values would be after. Here is what I got first try...


Looks bad I know, instead of finding the height values from the height map image, I randomly set the values between 0 and 100 for each vertex; this was the result. Green probably wasn't the best choice either. At least I knew something was drawing which was a start. I then went about getting the pixel information to work, and I solved it with this little method:


get_pixel(SDL_Surface *surface, int x, int y)
{
Uint8* p = (Uint8*)surface->pixels + 3 * (y * surface->w + x);
return *( Uint16* )p;
}

Here you pass in your SDL_surface that corresponds to the image you have loaded, and the x and y values of the pixel you want to find (the coordinates of the pixel), you next store the pixel information in a pointer to an integer, (the pixel value is stored as an int) and then return it.

Once you have all those values (stored helpfully in a two dimensional array) you simply have to put them into the appropriate place in your drawing code, (which I had finally figured out after several hours of research and bouts of trial and error). I finally got something that looked like this, based on the height map below.


I was skipping and dancing around after I first got this to work. There was no lighting, I was just incrementally increasing the colour from dark to light in each triangle I drew. I then went about getting the lighting code to work, and finally ended up with this:


Success at last! I understand it does kind of obscure the playing area but you get the idea! I have to thank www.videotutorialsrock.com for a lot of information on height maps and techniques on how to create such an effect, I will hopefully be able to move it out of the way of the grid soon too!

Tom out.

Sunday, 28 February 2010

Tower Defence ideas and a bit of code

Recently in my tower defence game I decided it would be cool to allow opposing players to place bombs over one another's towers in order to destroy them for a certain amount of resources. My thinking was that this would introduce an extra element to the gameplay where by a player has to balance their resources to afford new towers to fend off the enemies, as well as also trying to destroy their friends towers to make life harder for them.

I wanted to implement the bombs so you could have as many as you wanted at a time, so as I have done with my enemies and my towers I created a good old c++ vector (a smart array, or simply a form of container for my data) that could then be iterated through to update them.

I ran into a bit of a problem when I wanted to remove a tower and a bomb after the bomb had blown up the tower. I needed to know if the bomb I was on as I cycled through the list matched the tower, and therefore knew which tower and bomb to remove.

Here is the code I am using, you probably won't understand it, and it probably isn't the most elegant way of doing it, but by joe it works!


void CGameController::Update_Bombs( CTimer* timer )
{
for( unsigned int i = 0; i < _bombs.size(); ++i )
{
_bombs.at(i)->Update( timer );

if(_bombs.at(i)->get_exploded())
{
         for( int j = 0; j < _towers.size(); ++j )
{
if( _bombs.at(i)->get_i() ==
                            _towers.at(j)->get_index_i() &&
    _bombs.at(i)->get_j() ==
                            _towers.at(j)->get_index_j() )
{
_grid->set_occupied( _towers.at(j)->get_index_i(),
                                 _towers.at(j)->get_index_j(), false);

         _towers.at(j) = _towers.back();
_towers.pop_back();

_bombs.at(i) = _bombs.back();
_bombs.pop_back();

break;

}
}
}
}
}

Basically what I am doing is iterating through all my bombs, I update each one in turn, and check if it has exploded. If it has indeed exploded, I then cycle through all my towers, and then do a comparison with the grid square of the tower and the bomb, to make sure they match, and then I remove both of them. It works perfectly, but only with the help of my friend 'break;'.

Without that helpful command, if the first bomb in the bomb list was matched with a tower halfway through the tower list, and the bomb was then removed, the tower list would keep iterating through, and would try and compare itself with a bomb that no longer existed! Not good! I got a horrible run time error, and panicked quite a lot, but then remembered I was missing a 'break;' and then suddenly all was lovely again.

If you can think or a far cleverer way of accomplishing what I am trying to do I would love to hear it, no doubt I am sure there is, but I am just glad it works, well mostly ;)

Tom out.

Saturday, 27 February 2010

Tower Defence Update

Firstly let me apologise for my lack of updates, I have been pretty swamped thinking about my project and working on my code of late. I kept coming to write an update but didn't feel like I had anything particularly great to talk about so I decided against it.

I thought now was as good a time as any as I feel as though I am finally making some head way on my project. I now have a game that two people can actually play in competition with one another. That might not sound like much, but now the game can actually be played I can start thinking about balancing all the variables I have carefully crafted into the game. Things such as wave speed and number, tower fire rate and damage, and resource costs can start being honed so as to create a well balanced and enjoyable experience. There is also the matter of polish with regard to the user interface and graphics of the game that will go some way to increasing the visual appeal of the game itself.

I will try and post some screen shots of what I have soon so you can have a look at it, hopefully it will change more and more in the coming weeks and months.

Enjoy your weekend

Tom out.