Sign in to follow this  
Samith

Design Issues and RTTI

Recommended Posts

So, in my game I have a list of every object in the game world. This list is simply a std::list containing CEntity pointers, Entity being the base class for all objects in the game. I have different derived classes, like CInfantry, CVehicle, CAircraft, CStructure, etc. Now let's say I direct a CInfantry unit to attack, I'll want it to have a different animation when it's attacking another infantry unit versus attacking an aircraft unit. That is only an example demonstrating how varied interaction between different types of entities is desired, I'm not asking for solutions to that specific animation problem. The main problem is that I want varied interaction between the different types of units. I don't want a unit's behavior towards a tank to be the same as it is towards a foot soldier. This issue is easily solved using RTTI, but the general sentiment towards RTTI is that it's bad/slow/too much overhead, etc. So, my questions: Is using RTTI that bad? Is it so slow that, in a game world with lots of collision detection going on (and thus lots of type identification happening) it will cause massive slowdown? This problem that I have seems like something that would come up a lot in game developement, is there an industry standard alternative to RTTI? Is my design just bad in general, is there a way I could design my game such that this problem doesn't arise? I've heard a lot about multimethods as a way around RTTI, but are multimethods that much better? They aren't natively supported in C++, so I don't know if they are something I should seriously consider (I would like my code to be portable, but it's portability is not essential). There, that's a lot of questions, any help is appreciated! Thanks in advance.

Share this post


Link to post
Share on other sites
My personal aversion to an RTTI solution in this case has nothing at all to do with it being 'slow'. It's simply a terrible, unscalable system. I suggest you refine it down from class types to a smaller superset of types-of-types. Instead of going Entity->Tank, your heirarchy would go Entity->Artillary->Tank. All in all, you will only have a few types of units. There are infantry, cavalry, artillary, fighter craft, gun boats, and carriers. Work with this smaller set, and you won't have to worry as much about scalability.

Share this post


Link to post
Share on other sites
Quote:
Original post by Deyja
My personal aversion to an RTTI solution in this case has nothing at all to do with it being 'slow'. It's simply a terrible, unscalable system. I suggest you refine it down from class types to a smaller superset of types-of-types. Instead of going Entity->Tank, your heirarchy would go Entity->Artillary->Tank. All in all, you will only have a few types of units. There are infantry, cavalry, artillary, fighter craft, gun boats, and carriers. Work with this smaller set, and you won't have to worry as much about scalability.

I try to work with as small of a set of classes as possible. Infantry, Vehicles, Aircraft, and Structures was about as small as I could get it. Then for each class there are potentially dozens of different units, all of which are defined in a data file. This is the best way I can think of that gives me a small set of hardcoded classes but a potential for a very large number of unique units. I think that's basically the goal you had in mind when suggesting to me to use "types of types". In your solution though, RTTI would still be utilized though, right? It would just be used to check the interaction is between an infantry and artillery, instead of checking if it's between a grenadier and a light tank. Am I correct?

Share this post


Link to post
Share on other sites
Double-dispatch would be the first thing I'd think of here (indeed, the wikipedia article even mentions it as the first example). Much easier to keep track of, even if it is slightly mind-bending at first glance.

You definatly don't want to do this with every individual unit that may exist, so abstract catergories like you mention are a good idea, all based on the higher level double-dispatch behaviour. You can derive the sub types from the main types but that also tends to get messy. A better and more manageable method might be to do a data-driven system behind each highly-configurable main type.

Share this post


Link to post
Share on other sites
You can use RTTI, yes. But RTTI does not neccessarily mean dynamic_cast and type_of. It can be something as simple as an integer member.

I would personally not even have specialized artillary/infantry/building classes; just a unit class. Everything would be data driven.

Share this post


Link to post
Share on other sites
Quote:
Infantry, Vehicles, Aircraft, and Structures


You'll have to decide what level of granularity is right for you. A problem arises when you have a unit that could be placed in more than one catagory, such as a turret. Is it a structure, or is it artillary? I'd probably put less importance on the catagory and more importance on individual parameters, such as, can it move? What kind of terrain can it travel over? What does it fire? Etc.

[edit]
Expanding on that; there aren't many things a unit can actually do.
It can move, and it can attack. You can determine what catagory a unit is just based on those two: If it can attack, but can't move, it must be a turret. If it can't do either, it's a building. If it can do both, you fall onto what kind of terrain it can move over. Boats move over water, Infantry moves over land, aircraft move over everything.

Share this post


Link to post
Share on other sites
Quote:
Original post by Deyja
Quote:
Infantry, Vehicles, Aircraft, and Structures


You'll have to decide what level of granularity is right for you. A problem arises when you have a unit that could be placed in more than one catagory, such as a turret. Is it a structure, or is it artillary? I'd probably put less importance on the catagory and more importance on individual parameters, such as, can it move? What kind of terrain can it travel over? What does it fire? Etc.

[edit]
Expanding on that; there aren't many things a unit can actually do.
It can move, and it can attack. You can determine what catagory a unit is just based on those two: If it can attack, but can't move, it must be a turret. If it can't do either, it's a building. If it can do both, you fall onto what kind of terrain it can move over. Boats move over water, Infantry moves over land, aircraft move over everything.

Agreed. I'd also like to point out that using something like the Visitor pattern (used in double dispatch) is very brittle; if you change the hierarchy at all you'll have to change a lot of functions. Data driven is definitely the way to go, not only do you save yourself work writing code, it's more extensible and understandable, too.

Share this post


Link to post
Share on other sites
I think the problem is a classic many-to-many relationship issue. I have not come up with any really earth shattering solutions to the problem. They all have drawbacks. Visitor/ Double Dispatch works well but doesn't scale up or change well (as mentioned). You might try a tabular approach. For instance, create a table of function pointers (that point to animation routines or whatever). Then when you need to react, you just look up the correct function for your units, something like (pardon my syntax):

lookup_table[ your_unit_type ][ his_unit_type ]( params );

This doesn't scale well either and the table needs to be premade before you start unit interaction.

What i would do is pick whatever method works for you but try to limit the "types" of objects to just a few. For instance, don't create a BazookaSoldier and a FootSoldier both. Just create a generic class of soldiers called Soldier and have the specific differences be determined by the data of the object, not the object's type (like Deyja said). This way other objects like a Turret can target a generic "Soldier" without the need to distinguish between different kinds of soldiers.

The point is: limit class distinctions to just a few. Otherwise bad things happen.

Share this post


Link to post
Share on other sites
Quote:
Original post by Deyja
Expanding on that; there aren't many things a unit can actually do.
It can move, and it can attack. You can determine what catagory a unit is just based on those two: If it can attack, but can't move, it must be a turret. If it can't do either, it's a building. If it can do both, you fall onto what kind of terrain it can move over. Boats move over water, Infantry moves over land, aircraft move over everything.

That's a great way to put it. I've been flipping back and forth from implementations with just a CUnit class and implementations with CInfantry, CVehicle, etc. Every time I choose one I start to think the other is more appropriate. I guess I should try and stick with just a CUnit class. I want this to be as data-driven as possible, but that's difficult to do without having tons of little tags for every aspect of the unit.

OrangyTang- Double dispatch is a pretty cool idea but sounds kind of difficult to do right. It's kind of complicated. I'll definitely keep it in mind for next time though, thanks for the link.

Share this post


Link to post
Share on other sites
Quote:
Original post by Deyja
My personal aversion to an RTTI solution in this case has nothing at all to do with it being 'slow'. It's simply a terrible, unscalable system.


You shouldn't have an aversion for RTTI. What you should hate is bad usage of the RTTI system. Using RTTI in a bad way breaks the OCP (Open Closed Principle. See Wushu's journal as he have a rather good entry about this principle), but not all RTTI uses do that.

Regards,

Share this post


Link to post
Share on other sites
I've got another situation here, what if I want to have something completely unrelated to the units in the game, like a particle system who's particles damage units when they collide. How would I go about doing this? I've come up with three solutions: One, I use RTTI or one of the alternatives like double-dispatch, all of which violate the OCP (very cool concept, something I'll definitely be taking into consideration from now on, thanks Emmanuel Deloget) to some extent, or I can make some kind of hack where I derive a CParticleSystem from CUnit then use some black magic to make it work somehow, or I can create a whole seperate list that just has CParticleSystems in it then check every element of the particle system list for a collision with every element of the unit list in main game loop. The third option is what I'm looking at doing right now because it only very mildly violates the OCP, and it's easy to understand.

What do you guys think?

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