Advertisement

Class / struct question for objects

Started by April 09, 2000 09:19 PM
11 comments, last by paulcoz 24 years, 8 months ago
I need to create some sort of structure or class to store all of the objects in a map in memory. I am thinking of reading in all of the world data (walls, cubes, doors etc..) and putting this into an array, but I would like some advice on the organisation. If I were to create an 'object' array and store everything in this one class then that would be fine, except that you might be using a lot of memory for parameters which are empty like this: object( objecttype wallsize doorangle waterspeed openspeed ) If I were to create a different class for each object then I fear I might have trouble when I come to doing stuff like a z sort to optimise the drawing order of objects - because the objects parameters are spread out over a number of separate arrays. Example: wall{ wallsize colour } door( openspeed doorangle rotatetrue } Any ideas on how to organise this? Paulcoz. Edited by - paulcoz on 4/9/00 9:29:26 PM
Well, I would suggesting creating a base Object class and then inhereting your specific objects from it.

class Object {  int z_order;};class Door : public Object {  int doorangle;};class Wall : public Object {  int wallsize;}; 

Then you can use a Object * array to do your z sort, but still maintain a Wall array for your walls, etc.
Advertisement
Curses, SiCrane beat me to it (only by a few hours)

I totally agree with him (sorry if you''re a her, SiCrane ). By having a base class Object, and deriving other object classes from it, you can have an array of pointers to Object objects, and then there is no need to have separate arrays for each object type (unless this makes it easier to access and change data members, in which case you can have separate arrays for each object type with pointers to the actual objects referenced by the array of pointers to Object objects.... shit that''s confusing )

Yes, this is the way to go... ah, polymorphism, what joys you hold.

thankyoubye

-------------
squirrels are a remarkable source of protein...
It sounds like you both know what I am trying to do, but Bad Monkey has confused me (no offense Monkey Man ).

How do you distinguish between (and refer to) values stored in the base ''object'' class and those in the ''sub-object'' class when they are combined in one single entity?

Is having an array of one of the sub-classes really that different to what I put in my second example? Isn''t that still keeping the different objects split up into different arrays?

I need your help again,
Paulcoz.
quote: Original post by paulcoz

How do you distinguish between (and refer to) values stored in the base ''object'' class and those in the ''sub-object'' class when they are combined in one single entity?


Why would you need to? If you make sure none of the variable names are the same, then you just refer to them by name as you would with any other struct or class.

quote: Is having an array of one of the sub-classes really that different to what I put in my second example? Isn''t that still keeping the different objects split up into different arrays?


I thought it was suggested to keep them all in the same array? Therefore, if you implement stuff like z-order in the base class, you can use that array cos you won''t need to know whether it is a door or a wall or a banana just to know its z-order. If there is something else where you need to know the type, try looking up RTTI or perhaps implementing a virtual method called GetType() in the base class which you override in each of the derived classes to return a variable saying what they actually are.
Perhaps telling you what I am trying to do would be helpful:

(1) read in all the map data from a file, putting all of the world objects into memory either:
(a) in a 'object' array which can contain any type of object, or
(b) in a special array for that specific type of object eg. cube, wall, door etc.. (for the memory reasons I mentioned previously).
Which one I choose depends on which structure makes step (2) the easiest.

(2) Draw all of the objects in the world.
(a) First check the order in which the objects should be drawn (front to back to minimise redraws) - this is done by checking the z-values in camera space which requires that you have access to an object's vertices.
(b) Check the type of object in the appropriate object array and run the correct code eg. for a cube run the cube-drawing code, for a sphere run the sphere-drawing code.

In 2(a) you obviously need access to the object's data, and whether or not the objects are in a big non-specific array or otherwise is irrelevent while you are reading the data in.

When you are telling the program what order to draw in, however, and objects are split over multiple arrays things becomes messy because you have to draw one object from one array, say wall[0] then one from the array door[3] etc..
Or, if the objects are read into a base object entity, won't that mean there are a whole lot of empty wall classes, door classes etc.. taking up memory like I mentioned before?

Can I apply what SiCrane and Bad Monkey suggested to this situation? I don't understand how these sub-classes work, sorry.

Paulcoz.

Edited by - paulcoz on 4/11/00 6:26:12 AM
Advertisement
Ok, let''s say I have the class Object like so:
class Object {  public:    virtual void Render(Surface *) = 0;    virtual int  GetZOrder(void) = 0;}; 

Because the two object methods are pure virtual, an object of class Object can never be instantiated. However, I define some subclasses:
class Door : public Object {  public:    virtual void Render(Surface *) {}    virtual int  GetZOrder(void) { return 0; }};class Wall : public Object {  public:    virtual void Render(Surface *) {}    virtual int  GetZOrder(void) { return 0; }}; 

(Obviously replace Render and GetZOrder with functions that work.) Now, I *can* create instances of Door and Wall, because the define the pure virtual methods in class Object. So when I read in the map data, I''ll create Doors and Walls. Because they both are inherited from Object, I can cast Door *''s and Wall *''s to Object *''s without a problem, and stick them in the same array. Something like
Object * objects[MAX_OBJECTS];int ptr = 0;while (still map data) {  if (next object is a door) {    Door * temp = new Door();    objects[ptr] = temp;    ptr++;   } else if (next object is a wall) {    Wall * temp = new Wall();    objects[ptr] = temp;    ptr++;  }} 

New I can loop through my objects array and sort by Z-order, then loop through and call the Render methods. Because they are virtual functions, even though I''m using Object *''s to reference the objects, the correct Door or Wall method will be called for Render() and GetZOrder().

Did that clear things up?
Bravo SiCrane

I''m glad you came up with that awesome explaination... I was about to go at it, but when I got to your post, joy filled my heart. My head''s a real mess sometimes, but I know what I''m getting at

This guy deseves a medal or something... that was better than the crap they tried to teach me at uni last year. Is the path clear now Paulcoz?

-------------
squirrels are a remarkable source of protein...
So instead of having an array of sequential objects, you have an array of sequential pointers to jumbled objects, right?

Two questions:

(1) SiCrane said "an object of class Object can never be instantiated" which I interpreted as *you cannot use the objects based on the Object class, you can only create other classes based on that class and use objects based on those*, then he used the following line:

Object * objects[MAX_OBJECTS];

Isn''t the array ''objects'' based on the Object class and therefore contradicting what he said? I hope it doesn''t sound like I am criticising, I am just trying to comprehend.

(2) Can the sub-classes and base-classes have different function names/purposes or do these virtual functions have to be exactly the same?

I obviously need to read some more about classes because I thought they were just the C++ version of the structure in C. Looks like they are more involved (I''ve only been using C++ for about five months!!!).

Thanks,
Paulcoz.
No, he's not actually contradicting himself, though it could seem like that if you're not familiar with inheritance and polymorphism. Basically, you can declare an (Object *), since that's just a pointer (= memory address) for an Object, but it doesn't really create an Object. You can not make an Object (either by declaring one, or using "new Object" with an (Object *)). Since you've left parts of Object undefined, making an actual instance of Object will fail to work. But, an (Object *) can be set up to point at anything derived from Object, which is what you'll store in the array he mentioned.

Yes, I would suggest finding a decent C++/OOP book to cover some of this material. There is a tremendous amount of stuff to cover, and some of it can be very difficult/confusing the first few (several? many?) times through.

You can add new functions to derived classes, but virtual functions should be called in the same way. The reason is that virtual functions are "smart". If you have a (Object *), it can point to anything derived from Object. And if you use it to call any virtual functions, it automatically figures out what type of Object it's pointing to, then calls that version of the function for you. This is how, like SiCrane said, you could stick all of your objects in an array of (Object *), then run through that array calling the render function. As long as each type of thing (wall, enemy, ...) is derived from Object, each one can provide its own render() function, and when you call ObjectArray[ n ]->render(), you don't even care what type of object it is, it will use the correct version for that object.

Hope this helps a little more, but I realize this is rather confusing. It takes a while to adjust to OOP from procedural programming sometimes, and getting a good book will definitely help.

-Brian

Edited by - osmanb on 4/11/00 11:44:28 PM

This topic is closed to new replies.

Advertisement