Sign in to follow this  
stitchs_login

Game Object Hierarchy

Recommended Posts

Hi,

I wasn't sure where to post this so thought the general forums might be a good place to start, first time poster.

I have a project in which I am making a 2-Dimensional simulation game.

One aspect of this requires the creation of objects in the scene, the hierarchy of objects is defined below


Object - superclass

Edible, Warm, Washing - subclasses of object, each with a value attribute e.g. Edible has hunger_value integer with a get method to return this attribute

[left]
[/left][left]This is the base hierarchy, object will contain all methods common to the subclass that inherit from its sub-classes:[/left][left]
[/left][left]Cow -- inherits from Edible[/left][left]Sheep -- inherits from Edible, Warm[/left][left]Tree -- inherits from Warm[/left][left]Pond -- inherits from Edible, Washable[/left][left]
[/left][left]I overcame ambiguity problems by declaring Object as virtual in the three object type sub-classes. The thing I want to achieve is the creation of a Vector of Object pointers which are is able to call get methods from the subclasses, without having to define them in the object superclass, is there any way of achieving this?[/left][left]
[/left][left]Thanks for your time.[/left]

Share this post


Link to post
Share on other sites
[quote name='stitchs' timestamp='1298403348' post='4777651']
The thing I want to achieve is the creation of a Vector of Object pointers which are is able to call get methods from the subclasses, without having to define them in the object superclass, is there any way of achieving this?
[/quote]

Only by:

[list]
[*]using something like dynamic_cast<> or other kind of RTTI (run-time type identification)
[*]creating a "fat" interface for Object (you have already dismissed this option, and quite rightly)
[/list]

both of which are equally gross.

Generally these days this approach to structuring programs is considered inferior to [url="http://en.wikipedia.org/wiki/Object_composition"]composition[/url] and [url="http://www.google.co.uk/#sclient=psy&hl=en&q=component+oriented+programming&aq=f&aqi=g2g-m1g-v7&aql=&oq=&pbx=1&psj=1&fp=d207d86176b7919"]component-based programming[/url]. I don't pretend that that is a simple answer to your question but I'm not sure there is a simple answer.

What [i]exactly[/i] are you trying to achieve?

Share this post


Link to post
Share on other sites
The objects in the structure will pass their information to a character on-screen, when they collide, each object has 2 or more values out of the four:

hunger_value,
warmth_value,
hygiene_value,

and happiness_value - this value is contained within object as every possible object will have an effect on the Character happiness.

There will be a hierarchal ordering put in place that means hunger_value is the most important and happiness_value is the least important, in relation to the Characters current 'needs' at the time. The vector of Object pointers that I propose to use can draw all objects on the screen at one time, however, because Object does not know about the sub-class methods, it can only use the method to return the happiness_value as a way of modifying Character 'needs'.

I don't want to have to create a vector of each object type: cows, ponds, trees etc. just to be able to call these methods as it would require the management of 5 separate vectors, which I believe would become to unwieldy in the further development stages. Coupled with having to place each individual object in up to 3 vectors, depending on their individual attributes it does not seem like the most elegant way of solving the issues.

I hope this is enough information.

Thanks for your time.

Share this post


Link to post
Share on other sites
[code]
class Object
{
public:
virtual void AffectPlayer(Player &p)=0;
};

class Thing : public Object
{
private:
int happy;

public:
void AffectPlayer(Player &p){ p.MakeHappy(happy); }
};

class WarmThing : public Object
{
private:
int happy,warm;

public:
void AffectPlayer(Player &p){ p.MakeHappy(happy); p.MakeWarm(warm); }
};

void f(std::vector<Object*> &obs,Player &p)
{
for(auto o=obs.begin();o!=obs.end();++o) o->AffectPlayer(p);
}
[/code]

Stop thinking in terms of accessing properties from your objects and using them and start thinking in terms of expressing your objects in terms of actions.

Share this post


Link to post
Share on other sites
Thank you for the help, it matches the requirements of my second stage of development and has helped me to conclude this portion.

It is my intention to homogenise the different 'Make' methods and place some form of hierarchical ordering inside this single method that places hunger > warmth > hygiene > happiness which, from pseudo coding, seems to make sense on paper.

I'll just have to wait and see if that paper logic works during implementation.

Thanks again for the help.

Share this post


Link to post
Share on other sites
Try to avoid subclassing just because additional members are added to the class, this can be achieved through some kind of dynamic property-mechanism in the Object-Class so when classes like Cow, Sheep,... differ just in data/properties/members they become unnecessary when utilizing the approach with properties. Dynamic properties allow to add/remove properties during runtime. Try to design as abstract as possible and then make distinction just by feeding different data to the object-instance e.g. through the constructor or setter methods.

Here my approach with dynamic properties. I decided to let Object "know" or dispatch the properties based upon their ids to the correct player-methods. Another approach would be to just send id and the value of the property to a playerMethod e.g. applyProperty( string id, int value ) and let the player-object dispatch but this would be maybe too generic.
The first approach introduces high coupling between object and player but i think in this case it's ok.

[code]
class Object
{
public:
struct Property
{
std::string id;
int value;
}

void addProperty( Property p );

void affectPlayer( Player* p )
{
iterate over all properties
for ( int i = 0; i < this->properties.size(); i++ )
{
Propoerty& prop = this->properties[i];
if ( prop.id == "hunger_value" )
{
p->handleHunger();
}
else if ( prop.id == "happiness" )
{
p->makeHappy( p.value );
}
else
{
assert( 0 );
}
}
}

private:
vector<Property> properties;
};

Object* cow = new Object();
cow->addProperty( Object ::Property( "hunger_value", 10 ) );
cow->addProperty( Object ::Property( "happiness", 0 ) );
[/code]

Try always to refine your design, the first attempt of a design is never ever that what it will be in the end. Refactor as often as you feel it is necessary to increase code-quality.

Share this post


Link to post
Share on other sites
Another approach, which i find from theoretical side very beautiful ( i hate string comparisons ) would be to utilize double-dispatch for applying data to the player. But beware, this approach is rather overengineered and only useful if the properties are really huge.

[code]
// base class of all properties, contains NO DATA!! only double-dispatch mechanism
class Property
{
public:
void applyToPlayer( Player* p ) = 0;
};

class Happiness : public Property
{
public:
Happiness( int value );

void applyToPlayer( Player* p )
{
p->applyProperty( this );
}
private:
// data
};

class Hunger : public Property
{
public:
void applyToPlayer( Player* p )
{
p->applyProperty( this );
}
private:
// data
};

class Player
{
public:
void applyProperty( Happiness* h )
{
h->someGetter();
...
}

void applyProperty( Hunger* h );
};

class Object
{
public:
void addProperty( Property* p );

void affectPlayer( Player* p )
{
for ( int i = 0; i < this->properties.size(); i++ )
{
Propoerty* prop = this->properties[i];
prop->applyToPlayer( p );
}
}

private:
vector<Property*> properties;
};

Object* cow = new Object();
cow->addProperty( new Happiness( 10 ) );
[/code]

Please note that properties in the vector now must be a pointer to support virtual-methods.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this