SFML community forums
Help => General => Topic started by: Wander on January 03, 2011, 02:43:08 am
-
I'm trying to create an RTS and I know I need a resource manager, but I'm not sure how to go about making one.
Anyone have any solutions? Algorithms?
Thanks. ;D
-
Could you elaborate? What do you mean with resource manager?
What are your concrete goals for the RTS? First try to have a better idea of what you want to manage, then find the optimal algorithm to do it : )
-
My main goal is to have a 2D, top-down RTS with textures all around. Rather high-quality textures at that.
I need it to be quick and efficient.
It will need to load textures, fonts, audio, and sprite sheets.
My main goal for the RTS is to just accomplish the game itself and learn as much as I can while I'm doing it.
-
Good thinking !
You don't seem to require a very advanced resource manager for that!
And it is definetly good to keep it simple, stupid!
You could just implement a ResourceManager class, which holds in a few containers with the data your game uses.
Because you're game will be running on the PC, and will most likely be lightweight(assuming that :) ), you could load everything you need into memory at once, (really)preferably at inititialization, to avoid desnecessary memory allocations during gameplay.
My tip for the containers:
(example for sf::Image objects)
vector< pair<string, sf::Image*> > ImageList;
then you would have a list of images, associated with a name, so you could query it later.
(Inserting a new image)
sf::Image img;
img.LoadFromFile(FileName);
ImageList.insert(ImageList.end(), make_pair(FileName, &img));
You could then make a search function, to get a pointer to the image you need, by using its name!
Hope it helps!
-
Is there a way to do this without pointers because I never did really understand them. :/
How would it know where to get the images from?
-
I will try to explain the use of pointers generally:
(If you have doubts, feel free to add me on msn)
So, when you declare a sf::Image:
sf::Image img;
... you are allocating some memory, you can check how much using the function sizeof, like this:
sizeof(img); //sizeof(sf::Image) is also valid! Function returns size in bytes
When you do this:
sf::Image *img = new sf::Image;
...you are also allocating memory, pretty much the same way as for how much you care!
After either declaration, there is a sf::Image in your RAM, now you only need to be careful about how you use it!
With the first way, the object is bound to the created sf::Image memory address automaticly, and you may call its methods without further trouble!
Now on what comes to pointers:
A pointer is a variable too! But because a pointer holds as its value an address, its value can be anything in the RAM.
Because the pointer has this capacity to point at different adresses, you can play at will, as long as your data have integrity of course!
sf::Image img1,img2; //just two images
sf::Image *pImg = 0; //Points at nothing, the NULL
pImg = &img1; //& meaning address-of, now our pointer knows about img1;
pImg = &img2;//and now, it knows where the img2 is!
img1.LoadFromFile(""); // Calling a method normally
pImg->LoadFromFile("") //Calling a method from a pointer! This would call the LoadFromFile of img2!
(*pImg); //the symbol on the left makes the pointer behave like a normal object, so you could do:
(*pImg).LoadFromFile(""); //and still be calling img2 method!
&pImg; // The address of a pointer even lets you acess the raw bytes!
//You don't need to point at sf::Image created staticly!
pImg = new sf::Image(); //This just throws a sf::Image into memory, and keep its address for future reference!
delete pImg; //This will destroy permanently the sf::Image pImg is pointing to!
Now applying to the resource manager example:
In the vector, you keep a pointer instead of the actual sf::Image because you can later reference to it, instead of copying , which is faster!
and the resources will all be centralized, everything used it there, and thats good for your organization, specially when a lot of resources are used!
Imagine your search function like this:
sf::Image* ResourceManager::SearchImage(string SearchFileName){
for(unsigned int i = 0; i < ImageList.size(); i++){
if(ImageList[i].first == SearchFileName){ // first is the string , in the pair
return ImageList[i].second; //you return the pointer to the sf::Image you are holding
}
}
}
Where you called the function, you just got a fresh pointer:
use it normally as a sf::Image
Sprite.SetImage(*pointerObtained);
I hope this clarifies it a bit for you!
-
You saved two images in one pointer. Is the pointer acting like an array or did you overwrite the first one?
-
Overwrite, a pointer holds one address, no matter what!
Commonly, a pointer to any structure has 4 bytes size in a 32 bits system, if i'm remembering well.
-
Okay. That last edit you put in confused me.
What is SearchFileName?
Can you really just say .first, . second, .third, etc to reference a spot in a vector?
if(ImageList.first == SearchFileName){ // first is the string , in the pair
What do you mean by 'the pair'?
-
SearchFileName is just a parameter that you would pass through the search function! Check now!
Notice this:
vector< pair<string, sf::Image*> > ImageList;
So, ImageList is a vector, a dynamic array which contains in each position a pair<string, sf::Image*>.
ImageList with 2 images loaded:
ImageList[0] is a pair<string, sf::Image*>
ImageList[1] is also a pair<string, sf::Image*>
When you reference the ImageList, being i a valid position, it counts as the pair, and you can check the pair values, using first and second, that will return objects you stored. Check STL and C++ documentation for a better information : )
http://www.cplusplus.com/reference/stl/vector/
http://www.cplusplus.com/reference/std/utility/pair/
-
Okay knowing all of this. How would the program know where to look for images and files and such? I'd have to give it a directory right?
-
Sure, implement a function that can load the images present in a whole folder! : )
http://msdn.microsoft.com/en-us/library/aa365200(VS.85).aspx
Check if that helps : ) Good night!
-
Okay, thank you very much! I appreciate you time and help! :)
-
Advice: Learn C++ first, then program games.
Sentences like "can I do this without pointers? I never really understood them" should NEVER come out of the mouth of someone who programs games.
-
Thats absolutely true! You should never skip that : )
Read and Learn a lot about everything related to gamedev until you have some confidence in your skills, then make games, and remember, start small.
But if you have time to spend in your self-taught education, i encourage you to prototype your RTS, then you will know what you need to learn from your failures!
Best of luck ;D
-
Haha! Well, I think I understand pointers now that he explained it, but I might as well go back and check and make sure. ;D
On the other hand. I do not understand a thing going on inside that directory code you sent. Lol!
Is there a class in C++ that just gives some members that allow for directory mapping?
EDIT: Do you think this will work?
#define NumberImages 10
class ResourceManager
{
std::string ImageDir;
sf::Image Images[NumberImages];
sf::Sprite Sprites[NumberImages];
public:
ResourceManager()
{
ImageDir = "./Images/*.png";
}
int loadImages()
{
for (int i = 0; i < NumberImages; i++)
{
if (!Images[i].LoadFromFile(ImageDir))
return EXIT_FAILURE;
Sprites[i].SetImage(Images[i]);
}
}
};
-
No, i don't think it will work, you are kinda hardcoding the number of images, you dont need to.
There is a way that you load ALL the images in there, no matter the format, i'll try to describe it, but notice you must be careful as you might end trying to load another file type into sf::Image. Make sure there are only images in the directory you're selecting : )
About the sprites, you shouldn't do what you are doing, you are creating one sprite per image, instead , store only the images and no sprites.
And in the game, whenever you need the sprite you create it, or even create them all at initialization, just associate the sprites with images when you need the sprites, not on image loading time, this way you can use the same image for many sprites, and save resources : )
Write a function like this:
void ResourceManager::LoadImages(string Directory){
WIN32_FIND_DATAA File; //Info about the file to read
HANDLE FindHandle = INVALID_HANDLE_VALUE; //Handle to find files
FindHandle = FindFirstFileA(string(Directory + "\\*.*")), &File); //find the first file in the directory(parameter 1) and store in file(parameter 2)
if(FindHandle == INVALID_HANDLE_VALUE)
return; //return because there was NO first file
//By now, you have the first file
string FileName = File.cFileName;
//You HAVE to make sure it is a valid file, because the special directories "." and ".." may appear!
//In case you obtained a good file, load it :)
//Also, directories will be counted as files! so, they will appear!
//No subfolders where you are reading : )
if(FileName != "." && FileName != ".."){
sf::Image img;
img.LoadFromFile(FileName);
ImageList.insert(ImageList.end(), &img);
}
//For the rest of files
while(FindNextFileA(FindHandle, &File)){
FileName = FileData.cFileName;
//Same verifications as the first file, and then load, pretty much the same
}
//Close handles
FindClose(FindHandle);
}
Finish the function by yourself, make sure you understand, even try to make it more powerful, by googling and exploring more properties!
Hint: try to make it recursive if you need it : )
-
Thank you. Lol! I didn't understand any of the code on that webpage. It looked so intimidating haha. It looks a lot simpler when its put out like this, so I actually understand it now lol. XD
I tried the docs for the commands on that page but the explanations were ridiculous.
Anyway, I'm getting one error after I fixed what was there:
error: cannot convert 'std::string' to 'const CHAR*' for argument '1' to 'void* FindFirstFileA(const CHAR*, _WIN32_FIND_DATAA*)'
The code is this:
std::string Directory = dir;
Directory += "\\*.*";
FindHandle = FindFirstFileA(Directory, &File);
I can't think of any possible way to represent a directory with a char. :/
The only thing I can think of is maybe a pointer? Unless I'm mistaken.
EDIT: I tried this to try to fix it and I got a different error. I don't know how to fix this. Lol. Sorry for all the trouble I'm causing you. :/
std::string Directory = dir;
Directory += "\\*.*";
void * DirP;
DirP = &Directory;
error: 'void*' is not a pointer-to-object type
-
std::string Directory = dir;
Directory += "\\*.*";
FindHandle = FindFirstFileA(Directory.c_str(), &File);
It's as simple as that, my mistake : )
the string member function c_str() will return it as const char * !
-
Okay. Thanks :D. Let me test it out in my code.
-
It works, but it keeps saying that its found a file and then I make it print the name of the file and it says the name is .
EDIT: Its in the wrong directory. I have the directory for my Images folder plugged into the function.
ResourceManager rm;
rm.loadImages("F:\\Programs\\OSP\\RTS\\v. 0.1.1");
-
Every directory contains two special files, which happen to be directories too!
. is Itself (Current Directory)
.. is Parent Directory
if you do c:\Games\..\ you end up in C:\
if you do c:\Games\.\.\.\.\.\ you always end up in c:\Games\
if you do c:\Games\Crazy\..\Crazy2\.\..\ you end up in c:\Games\
being Crazy and Crazy2 subdirectories of Games
Hope it clarifies everything : )
-
OH!! Okay!! I see. Thank you so much. I just finished programming the last bit of the manager. It works. I even understand pointers. ;D
-
Keep going! and keep posting news on your project :D
-
In this thread?
-
You would get more feedback if you make a thread only for your game in SFML Projects : )
-
Okay. If you're interested in my project, it is called The Core Passage