0
\$\begingroup\$

(Although I'm sure this is a common problem I really don't know what to search for. Composition is the only thing I could come up with.)

I've read over and over that multiple inheritance and subclassing is really, really bad, especially for game entities. If I have three types of motions, five types of guns, and three types of armoring, I don't want to have to make 45 different classes to get all the possible combinations; I'm going to add a motion behavior, gun behavior, and armor behavior to a single generic object. That makes sense.

But how far do I take this?

I can have as many different types of behaviors as I can imagine: DamageBehavior, MotionBehavior, TargetableBehavior, etc. If I add a new class of behaviors then I need to update all the other classes that use them. But what happens when I have functionality that doesn't really fit into one class of behaviors? For example, my armor needs to be damageable but also updateable. And should I be able to have use more than one type of behavior on an entity at a time, such as two motion behaviors?

Can anyone offer any wisdom or point me in the direction of some useful articles?

Thanks!

\$\endgroup\$
5
  • \$\begingroup\$ I'm confused by your examples. First, what do you mean by "update all the other classes that use [the new behaviors]"? Splitting one component into multiple ones, so you have to change all the objects that used the original component? And you started talking about armor as a component, but by the end it's an object that has components itself? \$\endgroup\$ Apr 5, 2012 at 5:16
  • 1
    \$\begingroup\$ Please provide small code example for each situation you describe. I will greatly help in understanding your problem (if there is one). \$\endgroup\$ Apr 5, 2012 at 6:09
  • 2
    \$\begingroup\$ -1 The articles you should read are linked on the left side of this page: gamedev.stackexchange.com/questions/4114/… and gamedev.stackexchange.com/questions/12529/… and gamedev.stackexchange.com/questions/14607/… for starters, unless you have something more specific to ask. \$\endgroup\$ Apr 5, 2012 at 6:19
  • \$\begingroup\$ "But how far do I take this?" As far as makes sense but no further. Make your code modular so it's easy to refactor. \$\endgroup\$
    – Tetrad
    Apr 5, 2012 at 6:36
  • \$\begingroup\$ blog.terava.info/past/2011/1/4/game_object_inheritance_in_cpp If you are using C++ this is a relatively simple/elegant solution. \$\endgroup\$
    – PhilCK
    Apr 5, 2012 at 8:26

1 Answer 1

1
\$\begingroup\$

Inheritance isn't a bad thing per-se, you just shouldn't start using it too far up the hierarchy. I usually mix them.

class Weapon{
    void Attack() = 0;
}
class Sword : public Weapon{
    void Attack(){...}
}
class Gun : public Weapon{
    void Attack(){...}
}

class Player{
Weapon* m_weapon;
Mover* m_mover;
Armor* m_armor;
...

void Update(){
    if(UserHasPressedAttackKey)
        m_weapon->Attack();
    ...
}
}

From there on I think about what else I need. For example, if I need my "behaviors" to be very generic (e.g. an armor that doesn't only mitigate damage but also sends lighning bolts to all nearby enemies every 2 seconds) I think about implementing a messaging system instead.

class LightningArmor : public Armor{
    void OnMessageReceive( Message message ){
         if(message.type == EVERY_2_SECONDS)
              useMassiveLightningAttack();
         else if(message.type == ATTACKED)
              mitigateDamage();
    }
    LightningArmor(){
         ListenToMessage(EVERY_2_SECONDS);
         ListenToMessage(ATTACKED);
    }
}

An event-messaging system allows you to be very generic. As long as you have the events your stuff can basically do everything. But of course it's much more work implementing that than keeping a rather static system like above.

If you need even more power (e.g. having 2 Movers/Weapons) at the same time you can use a container instead

class Player{
    std::vector<Behavior*> m_behaviors;

   ....
}

Instead of specifically calling m_weapon->Attack() you can now let it run solely through event messages. Regarding your question whether it's useful to have 2 Motion behaviors - it might be. For example, a second one could be used to simulate gravity (or any other directional force) by constantly trying to move you down the Y axis.

But the question is whether you really need that. If you're not sure you can always come back later and implement what other things you need.

If you own StarCraft 2 (or a friend does) you might want to look into their Map Editor. Their data portion basically handles everything with behaviors. It nicely shows the advantages and disadvantages - you can do everything with it, it just becomes a lot more complicated than other approaches.

\$\endgroup\$
1
  • \$\begingroup\$ I like the notion of slotting in behaviors, and having those behaviors respond to events (like targetables having a onTarget() callback()). \$\endgroup\$
    – whiterook6
    Apr 5, 2012 at 18:07

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .