This will be the final part for our Game Object classes and will cover factories and loading objects from a file at runtime
Last time we covered the great possibilities that polymorphism gives us and how we can make what would otherwise be a lot of code into nice reusable chunks of code. That itself was an extremely powerful idea and in this tutorial we will take it one step further.
This tutorial will show you how to use a factory, this is essentially a class that creates objects based on a value. In our case we will have each class override a specific method which returns their class type.
virtual void const char* GetClassType() { return "TypeName"; }
Due to the way we structured our states in the previous tutorial we essentially made it so that our state didn't need to know about the types of the game objects and they could be used through a pointer to their base class "GameObject". We were still having to hard code which objects we wanted to use into the Init() function which poses problems for maintenance and reusability, what if we could make it so that the state would load the objects it needed from a file therefore eliminating the need to recompile when we decide to add more objects. Also what if the objects themselves could also load their initial values from an external file. Sounds great doesn't it!
This is known as data driven design and is the goal of this tutorial. So open up your IDE with the previous tutorial project and lets get coding
Create 2 new files. File.h and File.cpp we will write our file loading and reading classes inside these files.
File.h
#ifndef FILE_H
#define FILE_H
#include <fstream>
class File
{
public:
bool Open(const std::string& filename);
bool GetInt(int* pInt);
bool GetFloat(float* pFloat);
bool GetString(std::string* pString);
bool EndOfFile() const;
private:
std::ifstream m_ifstream;
};
#endif
So looking at this class in a little more detail you can see that it has functions to open a file, read a string from a file, read a float, read an int and check if the end of the file has been reached. That should be all we need at this point. Also notice that all of the functions return a boolean value, this is necessary because there may be errors in how we structure our text files.
File.cpp
#include "File.h"
bool File::Open(const std::string& filename)
{ m_ifstream.open(filename.c_str(), std::ios::in);
return m_ifstream.good();
}
// use the GetString function and use atoi() to get its value as an int
bool File::GetInt(int* pInt)
{
std::string s;
if (!GetString(&s))
{
return false;
}
*pInt = atoi(s.c_str());
return true;
}
// return a float value
bool File::GetFloat(float* pFloat)
{
m_ifstream >> (*pFloat);
return true;
}
// If you have read from files before this should be pretty easy to understand, if
// not then a trip to msdn might be in order :)/>
bool File::GetString(std::string* pString)
{
char buf[10000];
while (true)
{
if (EndOfFile())
{
return false;
}
m_ifstream.getline(buf, 10000);
*pString = buf;
if (pString->size() > 0 && (*pString)[0] == '#')
{
continue;
}
if (!pString->empty())
{
return true;
}
}
}
// check if the end of the file has been reached or the stream has failed
bool File::EndOfFile() const
{
return m_ifstream.eof() || !m_ifstream.good();
}
Try to go through each line of this code and make sure you understand most of it as it will serve you well in the future. It took me a while to write it and get it to work so don't just use it by copying and pasting and never thinking about it again. But anyway we now have a way to load and read from files
Lets test it out using our game object class by creating two new variables
float m_positionx; float m_positiony;
Now we shall change our GameObject::Load() function slightly
#include "GameObject.h"
#include "File.h"
void GameObject::Load(char* filename)
{
m_pSprite = Sprite::Load(filename);
File newFile; // here we create an instance of our file class
newFile.Open("gameobject.txt"); // load the file
newFile.GetFloat(&m_positionx); // read the values from the file
newFile.GetFloat(&m_positiony);
}
Next we will create the gameobject.txt file, it is essentially just a basic text file which you can create in windows by right clicking inside a folder and then going to new->txt file and then name it gameobject.txt. This file will need to be in the same folder as the rest of your project. Since we are only loading 2 values from this file it is pretty basic at the moment
10 10
those values are going to be the game objects x and y position values. One more thing is needed to test this out and that is to slightly change our Draw function to use these values.
void GameObject::Draw()
{
Sprite::Draw(GameInst::Instance()->GetScreen(), m_pSprite, m_positionx, m_positiony);
}
Ok so now run the program and you will see that the objects are at the x = 10 and y = 10 positions. Change the values in the text file and run the program again, no need to recompile, WOW! this is great! Imagine the possibilities
This tutorial is to be continued but I thought I would release what I have so far due to the huge gap between this and the previous tutorial.
Don't fret though, we will be loading objects from files at runtime very soon!




MultiQuote






|