Advertisement

Easy? Struct question

Started by November 27, 2001 02:14 PM
10 comments, last by Peon 23 years ago
I was thinking of programming a simple 2D strategy games (like Civ, but far more basic of course ) and was thinking of using structs to hold the unit data. Actually, by the time I actually start I''ll probably be using classes but the question is the same. I understand (sort of) how to create an object and access it''s members: Unit tank; tank.hp = 55; I was wondering if it''s possible, however, to somehow declare unit on the fly. For example, what would I do if a player decided to build two tanks? Is it possible to declare a new unit, tank2, when it''s created? I was also thinking about using link-lists, though I don''t know enough about them to know if they''d do the job. Arrays would also work I guess, but it seems like an inefficient way of doing it. Anyway, lemme know if this is possible; any help is appreciated
Peon
//Create a pointer to a new tank
Tank *TheNewTank;

//Use the ''new'' reserved word to create a new tank.
TheNewTank = new Tank;

//Access its members using ''->'' instead of ''.''
TheNewTank->hp;

delete TheNewTank;

Just remember to delete it when you are finished with it.
You can store the new tanks in an array like this

Tank* ListOfTanks[10];
ListOfTanks[x] = TheNewTank;

Access each tank like this
ListOfTanks[x]->hp;

Hope this points you in the right direction. If you need more of an explanation, just say so.
-Dan
Advertisement

The problems with arrays and a changing number of objects
is, that you''ll have to allocate more memory than you
probably will need.
And aditionally, if a tank gets detroyed, and it`s the
tank in the mid of the array, you''d have so set some
boolean value as "free" for that array cell, and every
time when you want to create a new tank check every array
element wether it`s free, or used. Yes, this is inefficient,
and maybe, some time you`ve used all of your, let''s say 100 allocated tanks, what then? Just allocate 1000 from game startup?
No.

Linked lists are perfect for that.
You can add a Node (wich contains the data for one tank),
and, when it gets destroyed, just delete that node.


You could have a static array set up to hold x units at max. For this approach, you'd have to have some special unit value (like, maybe, hp == 0 and being in a certain state) to indicate which array positions are "empty". Then you'd have a function for creating new units that would search the array for an "empty" spot, and copy the appropriate values in that slot. The drawback of this is, of course, that you only have MAX_UNITS (a constant you define, of course) slots for units, and if the array is filled, no more units can be created. It's fast for both access and creation, requires no special memory considerations like deallocation, but lacks flexibility.

Another idea is, yes, to use linked lists or some other data structure for very flexible unit storage since it can expand and contract at will. If you do this, you'll want to make a linked list class to make item operations and traversal very easy. Performance for both access and creation is linearly dependent upon the number of items in there (linear access is effectively no worse than "normal" arrays, though), but you will have to make sure you deallocate your nodes, otherwise you'll have memory leaks.
...but don't make your own linked list...

Perhaps the best solution is to use an STL (Standard Template Library, something that comes with every C++ compiler that's essentially part of the language) container such as list . list is great because it's guaranteed to have the same performance and behavior characteristics of a doubly-linked list (since it's usually implemented that way). But the class is ready to use and has been tested thoroughly, so it saves you lots of time and effort, not to mention that it does the work of allocating and deallocating the nodes for you. Let me give you an example of how you'd use list

      #include <list>using namespace std; // all STL classes are in the "std" namespace// make a typedef to make unit list declarations easier;// in this case, we're making the typedef the same as a// std::list holding Unit structures.typedef list<Unit> unit_list;unit_list UnitList;void CreateUnit(int hp, int whateverelse){    // create a Unit object and initialize it with whatever was passed    Unit new_unit;    new_unit.hp = hp;    new_unit.whateverelse = whateverelse;    // add the unit to the end of the list    UnitList.push_back(new_unit);}void KillAllUnits(){    // we traverse STL containers (that don't provide    // operator[]) using iterators, which are conceptually    // pointers to each node in the list; we start at the     // beginning of the list (retrieved by the begin()     // function) and keep going until the iterator points to    // the imaginary element marking the last + 1 item in the    // list (retrieved by the end() function), and we can tell    // the iterator to point to the next node in the list using    // operator++    for(unit_list::iterator it = UnitList.begin(); it != UnitList.end(); ++it)    {        // to access the node that the iterator points to, just        // dereference the iterator; NOTE: although the        // (*ptr).member and ptr->member syntaxes are        // functionally equivalent, iterators provide only        // operator* (and not also operator->), since not all        // items that an iterator points to will actually have        // members        (*it).hp = 0;        (*it).whateverelse = 0;    }}  


I strongly urge you to use an STL container (don't wast your time on your own linked list when the STL already made a perfect one for you that requires no babysitting). Not only will you save lots of time in both programming and debugging, but they do everything you'd ever need them to.

Edited by - merlin9x9 on November 27, 2001 3:41:35 PM

Edited by - merlin9x9 on November 27, 2001 3:45:24 PM
That was a good explanation. Be VERY careful with linked lists if you use them though, its very easy to screw up when you''re using pointers. If you use classes then try doing something along the lines of this..
class Tank
{
public:
Tank (); // create a new Tank
remove_hps ( int x); //remove hits
destroy_tank (); //remove the tank from existence

private:
int hits;
Tank* Tp; //allows you to make a linked list
}
Then if you had a pointer to a tank called p, I think you''d do something like (*p).remove_hps(4); if you wanted to remove 4 hps from the tank.
You''d create a new tank as shown above..
If you use linked lists then remember to have a head pointer to the start of the list, a tail pointer to the end of the list, and NEVER move these pointers (one is always at the start, the other at the end), use a temporary pointer to point to whatever tank you want to add or delete and shuffle the head and tail pointers so they always point where they should.
Jon
Wow, thanks for all the help everyone I just got finished reading the posts and it looks like there are some great solutions to what I wanted to do. I really don't have a grasp of linked lists quite yet, so the part about STL was a little over my head. I do understand part of what was said, so I just saved the post so that I can come back to it when I learn a bit more I haven't actually tried applying it yet, but I think I understand the idea using structs pretty well. Anyway, thanks again!

EDIT: Okay, I played with it a bit and here's what I came up with:

    #include <iostream.h>//PROTOTYPESvoid CreateUnit(int hp);//GLOBALSstruct Tank{	int hp;};Tank* ListOfTanks[10];int x = 0;int main(){	CreateUnit(10);		cout<<ListOfTanks[x-1]->hp<<endl;	cout<<x;	return(0);} //end main()void CreateUnit(int hp){//Create a pointer to a new tankTank *TheNewTank;//Use the 'new' reserved word to create a new tank.TheNewTank = new Tank;//Access its members using '->' instead of '.'TheNewTank->hp = hp;ListOfTanks[x] = TheNewTank;delete TheNewTank;x++;;}	//end CreateUnit()    


This is how I imagined you would do it. I don't completely understand this yet obviously I tried writing a small program to see if I could actually use the technique before I go on. I was thinking I would call the function, create a tank, initialize it, and then display the hp of the tank. I was able to sucessfully display the hp sucessfully when I declared:

"Tank* ListOfTanks[10];"

locally in the CreateUnit() function. It didn't work as a global, however (I'm assuming I'm misunderstanding that statement) Right now, the code compiles but the output looks like:

-572662307
1Press any key to continue

The cout<< would print 10 I thought, since that's what I sent to CreateUnit(). Any ideas as to what I'm doing wrong?


Edited by - Peon on November 27, 2001 8:23:02 PM
Peon
Advertisement
Your approach (as in the code listing) limits you to 10 units. Why bother to dynamically allocate them? Allocation and deallocation takes time. Instead, consider the static array approach; in this case, the unit objects are allocated on the stack just once, and automatically freed by the system when the process terminates. That way you don''t have to continually allocate and deallocate. Then reserve some special single or combination of values in the Unit struct to represent an "empty" (available for holding the new unit) slot. Like if the hp is -1 or something, then it''s "empty."

However, I suggest that you take a few days or however long it takes to get the hang of the STL. It''s not that hard, and once you have it down, you''ll wonder how you got along without it...

...but since you probably won''t follow my advice on that one, go with a standard, static array to hold your units.
Merlin: I really do want to follow your advice because linked lists (well, STL in this case) seem logical to me, I''m just not sure I could handle them yet For example, this line you posted above is sort of... "intimidating"

for(unit_list::iterator it = UnitList.begin(); it != UnitList.end(); ++it)

Things like the :: (scope operator?) I don''t even understand I''ll look into it though, in the next few days. (Could you explain what''s happening there, just a little bit?) Like I said in the first post (or did I?), I''m a long way from even starting a game, I just want to get the hard part out of the way and learn some of the concepts so that I''ll begin to get an idea as to how to solve problems before I actually begin work on the game.

I understand your concerns about STL. Forget about it. Just limit the number og tanks/objects to a certain number (arrays).

No need to work with linked lists already !

The first couple of times you program something it should just work, NOT be efficient or "cool" code.

More experienced people tend to forget how difficult it was for them when they first started.

-------------Ban KalvinB !
Whew... my brain hurts from reading all this... I originally had this question too, but I''m not so sure I wanna know anymore
Half the people you know are below average.Trogdor the Burninator

This topic is closed to new replies.

Advertisement