Sign in to follow this  
sipickles

Multiple inheritance and Game Objects

Recommended Posts

sipickles    240
Hello, Can I run this past you? Here's how I am planning on making game objects, using Multiple inheritence: Base classes: BaseObject SelectableObject IntelligentObject MobileObject ContainerObject Derived objects: Player ship: Base + Selectable + Mobile + Container NPC ship: Base + Selectable + Intelligent + Mobile + Container Land Mounted Turret: Base + Selectable + Intelligent Boring Rock: Base Resource: Base + Selectable + Container etc I hope that is pretty self-explanatory. Does this approach make sense? What pitfalls should I expect? Many Thanks Si

Share this post


Link to post
Share on other sites
Baiame    220
This is exactly what I tried to do. The problem is that you have to tediously write a bunch of stuff that can be derived from a number of simple explicit and implicit parameters, or in other words, you have to do something that the computer can do. For example, each time you make a most-derived class (in your example "Player ship", "NPC ship", and so on), you need to write a constructor that calls the constructors of its parent classes.

So if your language is fully reflective or has a good code generator available, I'd say go for it. Otherwise you're going to have to find another good way (which I haven't found yet, despite exploring a bunch of possibilities).

Share this post


Link to post
Share on other sites
sipickles    240
Should I try to translate this into a more nested approach?

eg:


baseObject

| |

StaticObject MobileObject

| | | |

Dormant NPC Player NPC






This looks so much harder to implement! SO much more work due to myriad combinations!

Share this post


Link to post
Share on other sites
Dancin_Fool    785
Don't nest it. What you want to do is change those into components, and have your base object have a group of components which are selectable, intelligent, mobile, or container. Look into Composition rather then Hierarchical.

Share this post


Link to post
Share on other sites
Baiame    220
^ Which, unless you want to make your own dispatch mechanism (no doubt complex and/or with hefty maintenance), creates greater dependency between (component) classes, and is almost certainly slower than straight polymorphism.

EDIT- Oh yeah, I do agree that you shouldn't use a traditional hierarchy.

Share this post


Link to post
Share on other sites
Vorpy    869
In my opinion, the separation of player and npc into different classes is often a mistake. A human player and an AI controller both control ships, and a lot of systems will care about which ship the player is controlling, but the ship itself is pretty much the same regardless of whether it is player or AI controlled.

If you think in terms of components, the inheritance hierarchy of the 90's starts to look really pointless. Why do static and mobile objects need to be different classes? A message dispatch system isn't really significantly slower than trying to accomplish the same thing with polymorphism, and it can reduce the amount of redundant classes needed to accomplish things.

Share this post


Link to post
Share on other sites
oliii    2196
I'll forward two interesting discussions about aggregation/components/data driven designs, and deep hierarchies.

clicky

a shorter one with the links
clicky 2

Mind you, there are loads of ways to do things, and tons of articles relating to that sort of design. In fact, there are whole chapters in the Game Programming Gems and design pattern books dedicated to aggregate, component designs.

so in the end instead of looking like


class ShipPlayer: public ShipBase, public Selectable, public Mobile, public Container
{};

class ShipNPC: public ShipBase, public Selectable, public public Intelligent, public Mobile, public Container
{};

class TurretLandMounted: class TurretBase, class Selectable, class Intelligent
{}

class BoringRock: public Base
{}

class Resource: public Base, public Selectable, public Container
{};





you would have


class Component
{};

class ContextSensitive: public Component
{};

class Physics: public Component
{};

class Container: public Component
{};

class Controller: public Component
{};

class Ship: public Entity
{
ContextSensitive* m_context; // selectable, not selectable
Physics* m_body; // mobile, or static, or whatever
Container* m_item; // container item
Controller* m_controller; // player controls or AI (intelligence).
};

class Turret: public Entity
{
ContextSensitive* m_context; // selectable, not selectable
Physics* m_body; // mobile, or static, or whatever
Container* m_item; // container item
Controller* m_controller; // player controls or AI (intelligence), scripted path.
};

class BoringRock: public Entity
{
ContextSensitive* m_context; // selectable, not selectable, pickup
Physics* m_body; // mobile, or static, or whatever
Container* m_item; // container item
};

class Resource: public Entity
{
ContextSensitive* m_context; // selectable, not selectable
Container* m_item; // container item
};





All objects look very similar, so you could even make due to separating them into different entities, and have a way to differentiate them from the core entity base class.

In the end, you would have



enum ComponentClass
{
ComponentClass_Context, // contextual info (what differentiate a 'rock' from a 'ship').
ComponentClass_Physics,
ComponentClass_Controller,
ComponentClass_SceneNode,
ComponentClass_Container,
ComponentClass_Script, // interface to script commands
};

class Component
{
ComponentClass m_Class;
};

class Context: public Component
{};

class Physics: public Component
{};

class SceneNode: public Component // render information (model, anims, ...).
{};

class Container: public Component
{};

class Controller: public Component
{};

class Entity
{
list<Component*> m_Components;
Component* getCompoment(ComponentClass component);
};





There are many advantages, but also drawbacks. Making components talk to each other can be a pain (Physics would be interfaced by many components, notably the controller and SceneNode). but the advantages are not to be sniffed at. For example, when it comes to create objects from a script file, your EntityFactory and ComponentFactory are just script processors. Also, you can control the functionality of your objects via script commands through the controller component. It adds a lot of flexibility. You could have a talking rock for example :)

As for coding, it's great for re-factoring and re-using code. Some with more experience will chime in and correct me.

Share this post


Link to post
Share on other sites
stevemkrenz    122
I came on here because I have a very similar, if not identical problem.

I had the same idea (basically)

1 class called object, that has 4 purely virtual classes, living, physical, interactive and controllable.

the idea being that there are NPCs, which would inherit living, interactive and physical, the player would be living,physical and controllable. A health pack would be physical and interactive; A vehicle would be physical, interactive and controllable; etc.

All 4 virtual classes, that all more complex classes inherit the object class. The only reason it really exists is so that all the objects can be casted to a plain object and stored in the same array. Then when they are looped through, it could check each class to see if it was living or physical or interactive or controllable. If it was any of those, go through and run it's specific code.

Since the 4 base classes are virtual, every person type or player or vehicle would need to implement the inherited funcitions, so each living thing (for example) could check to see if it should interact with a health pack. A person interacts with a person differnetly that a person interacts with a health pack.

But, I'm starting to think that I should have an array of each of the base classes. So if a person is interactive, physical and living, a pointer of that class would be passed to each of the arrays. Since the pointer in each one would be referencing the origional class, it would be coherent.

There could be another object that assigns an id number to each object created, so when a person needs to be removed from the game/engine, it would go through each array, deleting any classes with the matching id number and the delete the origional class.

Coming on here and reading this thread and then writing out what I want to be able to do has helped me so much. Now to go see if I can make this work.

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