• Advertisement
Sign in to follow this  

Array of objects

This topic is 4226 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Advertisement
Hidden

void UnitLoad()
{
long end;
long unitnumber;
string line;
ifstream fin;
fin.open("units.txt");
fin.seekg(0,ios::end);
end = fin.tellg();
fin.close();

unitnumber = end/64;
CUNIT_INFO *Unit;
CUNIT_INFO unitinfo;
unitinfo.unitnumb = unitnumber;
Unit = new CUNIT_INFO[unitnumber];
fin.open("units.txt");
fin.seekg(0,ios::beg);
for (int i=0; i<=unitnumber; i++)
{
fin>>line>>Unit.name;
fin>>line>>Unit.id;
fin>>line>>Unit.health;
fin>>line>>Unit.movement;
fin>>line>>Unit.x>>Unit.y>>line;
}

}


And well I can't access it for any other function

Share this post


Link to post
Hello Crackingod,

I do not fully understand what you mean.

If Unit is a global variable then is should be available for other functions in the same file-scope (even beyond the file-scope, but with an addition external declaration).

The following should be possible:


#include <Windows.h>
// Other includes...

// Object definitions...
class CUNIT_INFO
{
public:
int unitnumb;
string name;
int id;
int health;
int movement;
int x;
int y;

};

// Global variable declarations
CUNIT_INFO* Units = NULL;
CUNIT_INFO Unit;
int UnitCount = 8192;

// Declare functions
void InitializeUnits();
void Update();
void DrawLevel();
void DrawUnits();

int main()
{
// Inits
Units = new CUNIT_INFO[UnitCount];

InitialiseUnits();

// Do game routine here

while(Quit == false)
{
// Do game updates
Update();

// Draw
DrawLevel();
DrawUnits();
};

// Free with 'new' allocated memory
delete Units;

return 0;
}

void InitializeUnits()
{
for(int i = 0; i < UnitCount; i++)
{
Units.id = i;
Units.health = 100;
}
}

void Update()
{
// Do game update
// Do unit position update
}

void DrawLevel()
{
// Draw level
}

void DrawUnits()
{
// Draw units
}






But the next is more elegant:



#include <Windows.h>
// Other includes...

// Object definitions...
class CUNIT_INFO
{
public:
int unitnumb;
string name;
int id;
int health;
int movement;
int x;
int y;

};

// Declare functions
void InitializeUnits(CUNIT_INFO* Units, int Count);
void Update(CUNIT_INFO* Units, int Count);
void DrawLevel();
void DrawUnits(CUNIT_INFO* Units, int Count);

int main()
{
CUNIT_INFO* Units = NULL;
int UnitCount = 8192;

// Inits
Units = new CUNIT_INFO[UnitCount];

InitialiseUnits(Units, UnitCount);

// Do game routine here

while(Quit == false)
{
// Do game updates
Update(Units, UnitCount);

// Draw
DrawLevel();
DrawUnits(Units, UnitCount);
};

// Free with 'new' allocated memory
delete Units;

return 0;
}

void InitializeUnits(CUNIT_INFO* Units, int Count)
{
for(int i = 0; i < Count; i++)
{
Units.id = i;
Units.health = 100;
}
}

void Update(CUNIT_INFO* Units, int Count)
{
// Do game update
// Do unit position update
}

void DrawLevel()
{
// Draw level
}

void DrawUnits(CUNIT_INFO* Units, int Count)
{
// Draw units
}




The are more ways, but these should work.

Hope this help,

Regards,

Xeile

Share this post


Link to post
Share on other sites
Of course you can't access it in another function. :)

See, you created the objects on the heap, so they're still around, but the pointer to them was created on the stack, and stopped existing when that function ended. Xeile's solution solves the problem, and if this is a class member function, making this pointer a member variabele will solve it as well.
However, don't forget to destroy this array when you don't need it anymore, using the delete [] operator. Otherwise, you've got a memory leak...

Share this post


Link to post
Share on other sites
As Xelie said, you're creating memory on the free store, which can be accessed, but the problem is, you're not returning any information on where it is. The "Unit" pointer is created in the local scope for the function, but when the function returns, the pointer is destroyed, therefore you have memory sitting in the middle of your program. So, if you wish to access it, you should return the address of the memory. This can easily be done by changing the return type to CUNIT_INFO*. So, change your function to:


CUNIT_INFO* UnitLoad()
{
long end;
long unitnumber;
string line;
ifstream fin;
fin.open("units.txt");
fin.seekg(0,ios::end);
end = fin.tellg();
fin.close();

unitnumber = end/64;
CUNIT_INFO *Unit;
CUNIT_INFO unitinfo;
unitinfo.unitnumb = unitnumber;
Unit = new CUNIT_INFO[unitnumber];
fin.open("units.txt");
fin.seekg(0,ios::beg);
for (int i=0; i<=unitnumber; i++)
{
fin>>line>>Unit.name;
fin>>line>>Unit.id;
fin>>line>>Unit.health;
fin>>line>>Unit.movement;
fin>>line>>Unit.x>>Unit.y>>line;
}

return Unit; //Returns the address so you can use the memory.
}

CUNIT_INFO* Unit = UnitLoad(); //Now you can use this GLOBAL SCOPE variable
Unit[1].name = "Hiya"; //to access the data

Share this post


Link to post
Share on other sites
crackingod - this is off topic but I am a bit concerned by the logic in your unit loading function. You appear to be getting the size of the file in bytes, then dividing this by 64 to get the number of units.

You are reading a text file so I can't really understand how the length of each unit's details in the file would be exactly 64 each time.

I don't quite understand all this:

fin >> line >> Unit.x;

stuff either, unless you have a name for each attribute in the file that you are ignoring. You know this line will read in two whitespace seperated words, and discard the first since line is a local variable?

Sorry if I have misunderstood the way your file format works. It just looked a bit "wrong" at first glance.

Share this post


Link to post
Share on other sites
Hidden
Hi, thanks for your reply.
I started looking into unit stuff before you replied onto the other topic, so I thought that a dynamic array to store all the unit info would look nice.
My text file basically looks like this for the units:


Unit: Settler
Id: 1
Health: 100
Movement: 1
Position: 3 3
*
Unit: Warrior
Id: 1
Health: 050
Movement: 1
Position: 3 3
*



It is basically for easier reading/editing.

So yes, the size of each unit until the star is 64, the point being that the name tag will always be of fixed size, like the health etc... (for example 050).
Now yes this looks dodgy but thats the first thing I thought and it works. Probably not the best way to do it I admit. If you have any ideas for the file reading?

Share this post


Link to post
Welcome to C++. (BTW, this really should go in For Beginners.)

Data file:

Notice no 'hacked' numbers or constrained-length strings. I also took out the labels, because they actually make the file *harder* to read. Finally, I made it be one entry per line, to avoid the need for '*' delimiters.


Settler 1 100 1 3 3
Warrior 1 50 1 3 3


Reading code:

Notice how the reading is done by grabbing individual lines and re-parsing them. This is less efficient, but I usually recommend it as being much less error-prone. In particular, this makes sure that file reading for each line starts at the proper beginning of each line (if you read into a number at the end of a line, it will leave the newline on the stream, which would be picked up by a subsequent getline() call).


struct Unit {
// If it's just going to be a collection of data, then just use a struct.
// However, you really should take the time to learn some proper class design.
// Note that it makes no sense at all to store the "total number of units"
// into every Unit.
string name;
int id;
int health;
int movement;
int x;
int y;
};

// I encapsulate the process of reading a single struct from a stream, thus:
istream& operator>>(istream& is, Unit& u) {
return is >> u.name >> u.id >> u.health >> u.movement >> u.x >> u.y;
}

// Now, we return the objects, in a standard library container:
// std::vector comes from <vector>
// std::istringstream comes from <sstream>
// By using the vector, we never have to add our own code to track the number
// of units: we can always ask it for its .size(). As well, the memory
// management gets done for us.

vector<Unit> readUnitsFromFile() {
fstream fin("units.txt");
vector<Unit> result;
string line;
while (getline(fin, line)) {
istringstream ss(line);
Unit u;
ss >> u;
result.push_back(u);
}
return result;
}

Share this post


Link to post
Share on other sites
Hidden
Hey, thanks a lot, that works perfectly.
So now I manage to load both my map info and my unit info.
To display the units on the map, I was thinking about checking each time a cell was created wheter a unit existed on that cell (by checking position) and if so draw the unit.

Share this post


Link to post
Well as discussed in the other thread, unit information and map information are seperate things and should really be maintained seperately until they are drawn.

I stand by my suggestion in the other thread that you use an offscreen buffer to draw your map to, then iterate through your units sequentially and draw them onto the buffer, then draw the buffer to the screen.

Post here or there if the way I explained it (in the other post) does not make sense.

Share this post


Link to post
Share on other sites
Hidden
Hey again, and thanks for your reply.
I actually used a mix of your idea and Zahlman's.
I'm using your way of storing and drawing the map (the first one you showed on the other topic) but I am using a vector to store the unit inf which proves to work quite well.
I managed to add a couple of things, such as movement, but I have one problem which might seem totally stupid.

As Zahlman showed, I used a vector to store the unit info:

vector<Unit> UnitLoad() {
fstream fin("units.txt");
vector<Unit> result;
string line;
while (getline(fin, line)) {
istringstream ss(line);
Unit u;
ss >> u;
result.push_back(u);
}
return result;
}



Now, the problem is that each time I want to access that data, I access it by calling that function: vector<Unit> Unit = UnitLoad();
So basically each time the info is recovered from the file.
The problem is, if I do movement for example, I am forced to rewrite to the file after each movement, so that I can use the modified coordinates somewhere else (that's what I'm doing right now, it workd quite well, but looks quite dodgy).
Anyway of retrieving the info from that vector without taking it from the file each time?
My idea is to rewrite everything to files only at the end of each turn!
Thanks a lot to all of you ;)

Share this post


Link to post
Each turn? That is madness dude. You only want to be loading it at the start of the game, and maintain it in memory, not in a file.

The easiest way to do this would be to have a global vector which you load into at the start, then just use throughout the rest of your code:


vector<Unit> Units;

void at_the_start()
{
Units=LoadTheUnits();
}

void during_the_game()
{
for(int i=0;i<Units.size();++i) HandleUnit(Units); // just use it
}



I should also point out that your current method of loading creates a local vector in the load function, then copies the entire thing into another vector when it returns. If you have a global Units vector, you would be better to rewrite the load function to just load into it directly instead of a temporary:


vector<Unit> Units;

bool UnitLoad() {
fstream fin("units.txt");
if(!fin.open()) return false; // note you should be checking this in
// case the file open fails for some reason

Units.clear(); // not strictly needed if only called once but good practice

string line;
while (getline(fin, line)) {
istringstream ss(line);
Unit u;
ss >> u;
Units.push_back(u);
}
return true;
}



People may start shouting at me now for suggesting using a global variable, but if this is a simple project, and the vector is local to just one translation unit, I don't think it would be worth complicating things at this stage.

HTH

Share this post


Link to post
Share on other sites
Hidden
Thanks, it works very well.
So you suggest to write info to file only when the user quits the game?
Well anyway thank you, I'm gonna try and get more stuff done like movement, resource collection etc...
Thank You

Share this post


Link to post
Hidden
I have another question.
I can now load and display a map on screen, display units, "select" them, and move them around with a limited number of movements per turn.
Now, I'm going for buildings. I wonder how I should do that. Should I create another text file and access it as I did for the units? Starting with an empty file and writing into it each time a building is created?
Or simply store all building info into a vector and then only in the end output everything to a file?
Since I'm limited (for the moment) to one symbol per tile I don't want to mess with more than one object for each tile.

Share this post


Link to post
I guess it depends. If your buildings are dynamic i.e. can be created and destroyed, there might be an argument for storing them in an array like the units.

Then again, if the map became quite large and had a lot of buildings on it, it might be more efficient to have the buildings stored as part of the map, since you could just examine the map directly for collision detection etc rather than having to iterate through the list.

I'd just do whatever feels the most natural for the type of program you are writing. You seem to be doing fine so far.

Share this post


Link to post
Share on other sites
As a topic about being introduced to arrays, this thread is probably more appropriate in For Beginners, so I'll move it there.

Share this post


Link to post
Share on other sites
Hidden
Quote:
Original post by EasilyConfused
I guess it depends. If your buildings are dynamic i.e. can be created and destroyed, there might be an argument for storing them in an array like the units.

Then again, if the map became quite large and had a lot of buildings on it, it might be more efficient to have the buildings stored as part of the map, since you could just examine the map directly for collision detection etc rather than having to iterate through the list.

I'd just do whatever feels the most natural for the type of program you are writing. You seem to be doing fine so far.


Hmmm but if I want to store the building info in the map, I should look for another way to store the map right?
Cos for the moment I can't have more than one object per tile the way the map is stored.
Anyway I think I'm gonna stick to a 5*5 map for the moment and implement all the stuff in there before going more graphical (which should make some things easier to show on screen rather than going through symbols and stuff).
But I want to get the game logic right under simple text mode before moving to graphics stuff.
What do you think?

Share this post


Link to post
Sign in to follow this  

  • Advertisement