Archived

This topic is now archived and is closed to further replies.

Creating an Entity Hierarchy

This topic is 5130 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

Staying true to an object oriented design, I believe that anything that can be represented in the game world should be an entity right? So in my game, that includes creatures, fireballs and items etc. Thus I have a hierarchy like this: Entity |-Creature |-Projectile |-Items By doing this, I am allowed to select, draw, process all entities like they were all the same. So it''s good yes? However, I also want to use a Flyweight kind of concept by seperating the intrinsic and extrinsic states. So perhaps the GoblinFlyweightClass would contain total hitpoints, but GoblinContext would contain current hitpoints. But if I go this route, we''d end up with a lot of classes, because each type of creature, projectile and item will require two classes. What would be a good way going about this that would require just one class per concrete entity?

Share this post


Link to post
Share on other sites
Hi;

Are you sure you want all of these entities to inherit from one base? If so, what should this base represent? What common facilities should it offer the entities?

I see you mention selecting and drawing the entities as part of the interface of the class. In my opinion this should be handled by other classes, as it allows you to seperate game logic from representation (The part that contains most platfrom dependent code) and therefor ease portability and customization.

As for having multiple objects representing the same entity, it can be quite useful in keeping your architecture clean. For example, You can have one class define ''Creature'' as an entity to handle interaction with the system (e.g. Location on the map, inventory...etc not to mention memory management and low level system details). and another Creature class that handles interaction with the game mechanisms (Being hit by a sword, casting spells...etc)

Another thing to consider is that you don''t have to have every race be a seperate class, as in:

Creature:
|-Goblin
|-Human

Is there anything inherently different in the implementation of Goblin and Human? Can you represent these differences as differences in values between similar objects? If so, you''ll find that your heirarchy won''t necessarily explode out of proportion and it would be much easier to expand the game (with more monsters, objects and terrain types)

Peace Out!

Share this post


Link to post
Share on other sites
Hmm yes, but remember that I''m still using a Flyweight sort of pattern and that the extrinsic state might have to store different values. For example, a gargoyle might have a Stone state, while a phoenix might have an extra life. All these will be represented for in the Flyweight (which stores intrinsic state). But how do I cater for this extra variables that not all other classes will have?

I have thought storing everything using a char pointer and access everything using offsets. I can store as much or as little as I want. But this could be dangerous and has inherent design flaws.

The base class also provides transparency for the functionality of drawing, processing selections, detecting collisions etc. My graphics manager does a good job of seperating game logic from representation. But wouldn''t it be a good idea to draw all entities in a single pass?

Currently the project is in 2D, though we are switching to 3D later. So while in 2D mode, there''s the thing about z orders and graphics will have to be drawn in order. This is one benefit of having all entities inherit from a base class and managed in a sinle manager.

Share this post


Link to post
Share on other sites
If you''re just storing data in the concrete portion of the flyweight, and you don''t require methods in the flyweight, why not just use static member variables which are constant(or not I suppose...)? That will allow them to be shared among all instantiations of a particular class, while not being duplicated for each one, I think that''s what you''re after.

Ravyne, NYN Interactive Entertainment
[My Site][My School][My Group]

Share this post


Link to post
Share on other sites
Well there are functions in the Flyweight''s but your idea could work too, if I put those functions in the client classes. I''m not sure how that would result in?

Actually if what you said was true, why would anyone ever need Flyweights? *raises eyebrow*

Share this post


Link to post
Share on other sites
first things first. An entity should never know how to explicitly render itself. Your code will be far more easier to follow if you have something like


CBaseEntity
protected:
int ModelIndex
int SkinIndex
vector3 Position
vector3 Angle
vector3 BoxMin
vector3 BoxMax
int Frame


Then, when you want to change the model or the skin, you can do

ModelIndex = Graphics->ModelMgr->Load (Name)
SkinIndex = Graphics->SkinMgr->Load (Name)

Finally, declare your rendering class (which should be inside the graphics class) as a friend of CBaseEntity, and voilla - You''ve taken the rendering code out of the game code.

If you don''t want to use friends, then just provide a Get () method for each of the variables required for rendering.

Regarding selection: I am currently working on an AI Editor that allows new entities to be added via loading of DLLs. Each entity is inherited from CBaseEntity, meaning I can put all the selection code in the UI and it''ll work for any type of entity. However, each entity can export a menu that allows the user to set it''s properties.

Then again, maybe not. Up to you.

Share this post


Link to post
Share on other sites
I dunno, I''ve never come across a good use for them myself. I prefer using static member variables, it keeps everything in the class, and has less indirection to the intrinsic data. If you needed flyweight functions, and you had 2 or more similar classes that shared those functions and/or variables, then they would make sense I suppose, but I think the method I stated is cleaner and far easier to follow. No wasted memory, no confusion, no extra inheritances or class pointers... and, IMHO, those flyweight functions are better off as member functions of the class anyhow.

flyweights were probably conceived for more complex situations than tracking MaxSTATs and the like, and what I suggested sounds like enough for what you want. Decide for yourself though.

Ravyne, NYN Interactive Entertainment
[My Site][My School][My Group]

Share this post


Link to post
Share on other sites
MENTAL: My entities don''t know how to render themselves explicitly. Instead they use a Renderable object which accepts a graphic ID. And they control how the Renderable is drawn using frames and whatever.

Also my question is on how to structure the classes such that introducing one class will give you a new concrete entity. =p

Ravyne: I''ll consider it and ask around a while more. =p

Share this post


Link to post
Share on other sites
Make a single base class called "WorldObject" or something similar, and have everything derive from that. Override only two pure virtual functions, Update and TouchFuncion. I *guarantee* you won't get around to implementing any of these entities if your class hierarchy is too complex. If you think about it, everything you could possibly want to do can be contained in Update and TouchFunc.

[edited by - Shadow12345 on November 28, 2003 2:57:13 PM]

Share this post


Link to post
Share on other sites
shadow12345: So everything should just directly inherit from that? I don''t think adding one layer that determines if they are creatures, buildings and items will make it that more complex.

And I''ve thought about it and have decided to do away with Projectiles. So right now, we have Creatures, Buildings and Items. Pathfinding will also avoid creatures and buildings.

Also, you didn''t say if using static functions like Ravyne suggested was a good solution. I imagine, that it would be quite obscure to other programmers who''ll read the code.

Share this post


Link to post
Share on other sites
quote:
Original post by Darkor
Also, you didn''t say if using static functions like Ravyne suggested was a good solution. I imagine, that it would be quite obscure to other programmers who''ll read the code.


static member variables the functions couldn''t be static or you''d have no access to them outside the class file. Just clearing that up. I don''t think it would appear obscure to anyone, in fact I find it more straight forward.

but again; evaluate the options and choose what seems best.

Ravyne, NYN Interactive Entertainment
[My Site][My School][My Group]

Share this post


Link to post
Share on other sites
darkor: i have actually implemented a complex entity system, and that is what I personally used, and it worked. do whatever you want, but remember you want to be spending all of your time defining entity behavior, not deciding the perfect hierarchy system (because ultimately there isn''t any).

Share this post


Link to post
Share on other sites
shadow12345: Haha, I didn''t say it would work, but you see I have other programmers on the team and they would be doing the implmentations, not me. So I have to make the hierarchy do as much as possible in order not to erm let them screw it up. Though I concede the fact that this is impossible because anyone who would want to screw things up could do so.

But that''s not the point, I simply want to make it such accidents don''t happen. =p

Ravyne: Yes, I''ve discussed it with the other programmers and though they find no reason not to use static stuff, they say that it''s not really a good design. I disagree, since this way makes classes more closely knit.

What I mentioned about it being obscure is that, you don''t really know what the class is. It can be an instance and thus the actual entity or it could be used for the static members as a Flyweight.

I guess I still have some sorting out to do. I have other things to code in the meantime so don''t worry, I''m not wasting my time just doing thinking. =p

Share this post


Link to post
Share on other sites
the only advice I can give is play around and see what works. Personally, for me, I have a higher success rate when I keep things as simple as I possibly can. Your hierarchy should make things easier for you, not harder.

Share this post


Link to post
Share on other sites
Hmm well I''ve thought about it and the only reason to use Flyweights in this case is to allow designers to create variations of the same entity to exist at the same time.

Imagine if static variables were used, you can only have one type of entity per class. If say you had a manager for loading and unloading flyweights, a designer can take an existing entity and change it and both would exist and use only one class.

My game could probably use that kind of functionality, so I''ll use flyweights.

shadow12345: Yeah keeping it simple is great, but as I mentioned, making it simpler in the long run is worth the trouble now.

Share this post


Link to post
Share on other sites
I found this article Smash TV 3D Design quite informative.

It pretty much describes what you want to achieve and also flattens deep inheritance hierarchies and replaces them with a containment / systems approach.

I guess it's up to you if you go the 1 class / 2 classes approach. I went with 2 - Actor and ActorData, with Actor having pointers to the data which is stored in a std::map.

I limited my inheritance to 3 levels...
e.g.


Actor::Alien::Lander
Actor::Alien::Mutant
Actor::Bullet::Missile
Actor::Bullet::Laser
Actor::Ship::Standard
Actor::Ship::Fast
etc

CDataStore < ActorClassEnum, ActorData >
CDataStore < ActorClassEnum, AlienData >
CDataStore < ActorClassEnum, LanderData >

< ACTOR_CLASS_LANDER, CLander >
< ACTOR_CLASS_MUTANT, CMutant >



When creating the Entity I'd set the pointer to the relevant data...


this->actor_data = CDataStore < ActorClassEnum, CActorData > ::getData(ACTOR_CLASS_LANDER);

this->alien_data = CDataStore < ActorClassEnum, CAlienData > ::getData(ACTOR_CLASS_LANDER);

this->grunt_data = CDataStore < ActorClassEnum, CLanderData > ::getData(ACTOR_CLASS_LANDER);

Seems to work quite well for my needs.

Cheers,
Paul Cunningham


EDIT - fixed the greater / less than signs

[edited by - PaulCunningham on December 1, 2003 8:19:00 AM]

Share this post


Link to post
Share on other sites
Ah just when I''ve thought of almost the same solution, you posted that! =p It was a good read, thanks.

Well already we are implementing such a system in the Flyweight. However, that is not the problem. I realise that I can avoid having two classes for each type of entity, by putting as much functionality into the Flyweight instead of the Exported state.

That being said, all entities in the game are treated the same way, but the Flyweight controls its behaviour. I will have an implementation up soon.

Also if certain entities require more than the default processing, we don''t have to subclass it to create distinct behaviour, instead the Decorator pattern uses object composition to change behaviour. But I''m not sure if this is needed yet.

Share this post


Link to post
Share on other sites