7
\$\begingroup\$

I'm trying to create a simple turn based console (command line) game but I'm confused of what approach to use when creating classes for objects. My concern is maintainability and flexibility.

First Approach:

class Weapon{
    ...
}

class Sword:Weapon{
    ...
}

class ShortSword:Sword{
    ...
}

class TwoHandedSword:Sword{
    ...
}    

class Axe:Weapon{
    ...
}

class HeavyAxe:Axe{
    ...
}

Second Approach:

class Sword{
    SwordType type;
    ...
}

class Axe{
    AxeType type;
    ...
}

So which is better, first or second? Why?

Important Note: I'm a beginner in game development.

\$\endgroup\$

4 Answers 4

11
\$\begingroup\$

Essentially what Aron_dc said, though I would go even farther. Generally you should try to keep your class-structure as shallow as possible and separate code(algorithms) from data(attributes).

You only need one weapon class for melee/instant-hit-weapons. This class can either instantly check what it hit, or is given an object to apply damage to. This includes ranged weapons, that are insta-hit, like a laser (a gun might be too, if you don't want to model it too realistically).

class InstantWeapon{
  Sprite sprite; //should be inherited from EquippableObject, or DrawableGameObject, or something
  WeaponType weaponType;
  DamageType dmgType;
  Double dmgOnHit;
  ...

  void Hit(ObjectWithHitPoints o){...}
  void Hit(Ray hitRay)
}

A second class is used for particle-spawning weapons, such as a wand of fireball. These weapons don't damage directly, but instead spawn a new object that moves according to its own logic and does damage when it collides with an object. In this case the particle holds all information needed (damage amount and type, radius etc) and it makes it easy to give them custom logic (homing missile, or loosing damage the longer it travels, ...)

class ParticleSpawner{
  InteractiveParticle sampleParticle;

  void Fire(Vector3 position, Vector3 direction){
    ParticleEngine.Add(sampleParticle.Clone());
  }
}

Depending on how complex you want your weapon and damage system to be you can have a look at the component pattern. The basic principle is that you would have one Weapon class and a list with multiple instances of the DamageComponent class. The DamageComponent class holds the algorithm and data for all weapon effects that apply to this one weapon.

class Weapon{
  List<DamageComponent> damageComponents;

  void Fire(Ray hitRay){
    foreach(component : DamageComponent)
      component.Apply(hitRay);
  }
}

Each component can now spawn a fireball, reduce enemy armor, do standard damage, apply an "on fire" effect to targets, etc. Additionally each component can handle the weapon-swing the way it wants. Get only the target directly in front, or cleave in a wide arc, etc...

Also note that the component system can come in handy in other places.

  • Different types of armor components protect differently against different damage types
  • Particle on update components can influence a single particle in different ways
  • Abilities granted by skills or objects only need to be implemented once, since they simply add the can-fly or the can-see-underground component to the player.

Generally it empowers you to create lots of small components that each on their own don't do much, but can form extremely complex systems, since their combinations grow exponentially with each new implementation.

The resulting effects of the system can become quite complex, which is nice, when you want emergent behavior and model things in a complex fashion, but that makes it harder to do things like weapon balance or enemy difficulty. For a popular example, look at Diablo3's with their random ability components. Certain combinations are way stronger than the others.

\$\endgroup\$
1
8
\$\begingroup\$

Disadvantages of the first one (subclassing):

  1. you clutter your code with many sublclasses, that you obviously don't need
  2. you have to keep track of your depth of inheritance (?) if you change something in your weapon classification hierarchy
  3. I don't think there are many advantages to this approach

Disadvantages of the second one (Strategy pattern):

  1. You still have many classes (but they don't stick as tough together as in the 1st variant)

Advantages of the second one (Strategy pattern):

  1. There are many ways of reusing your classes this way. Want a cannon that is also a sword? Just put the two types together in a class and implement a supertype SwordWithCannon ;) (you can't do that with the first approach that easily)
  2. Less code
  3. You could even change the behaviour of the weapon during the game. So your Sword gets blunt, just change the swordType to "bluntSword" (or something similar)

If your weapons only differ in some stats, you dont have to use any of this. Just put the stats in the base class and fill them accordingly to your wishes (boolean twoHandedness,int damage, String name, ....).

\$\endgroup\$
5
  • \$\begingroup\$ I this is far from the question but it's actually related. How should I store data? Say I have an inventory, should I store weapons, armor, in one table even though they are of different types? Armor has defense, weapon doesn't have, if I have columns defense and damage, one shall not have a value (null), that is a bad database design. \$\endgroup\$
    – kazinix
    Commented Jul 30, 2012 at 9:19
  • \$\begingroup\$ What you describe is a wide table approach. You have all columns that you need for all the Items in one table and only fill those that are important for this specific item. Personally I would take a table "Inventory" that only holds ID's to other tables (that contain weapons,potions,spells, etc.). I'm not quite sure if you could use a forgein key relation there because the key would link to more than one table, but if it's programmed correctly you wouldn't need them. Is it a singleplayer or a multiplayer game? Maybe using a database is using a sledge hammer to crack a nut ;) \$\endgroup\$
    – Aron_dc
    Commented Jul 30, 2012 at 9:21
  • \$\begingroup\$ Or should I store them as binary? I'm thinking of making the classes serializable so that I can store them as XML. \$\endgroup\$
    – kazinix
    Commented Jul 30, 2012 at 9:22
  • \$\begingroup\$ Sorry, I'm used working with databases :D What alternative storage can I use aside from database? \$\endgroup\$
    – kazinix
    Commented Jul 30, 2012 at 9:27
  • \$\begingroup\$ Like you said you could use XML or just every format you can imagine yourself. You aren't constrained to exisisting formats, as long as you can parse your own format you can use it. If you don't want to invent an own format use XML or plain text files for the beginning. These are easily parsable. And you dont have to fiddle with big databases (for a small ammount of data). \$\endgroup\$
    – Aron_dc
    Commented Jul 30, 2012 at 9:37
2
\$\begingroup\$

If you only change parameters, then there is no need for inheritance. But, if you plan to add different functionality, then I suggest you use sub classes. I doubt that you will have additional functionality in a console game, only parameters such as damage and addsAttributes.

But this is really specific to the implementation.

\$\endgroup\$
2
\$\begingroup\$

I tend to avoid using inheritance as much as possible when it comes to classifying objects based on data used in games as opposed to classifying systems used in games. What I mean is, it may make sense to have a Animator class and then a SpriteAnimator and TileAnimator inherit the Animator if the behavioral differences will have to be hard-coded discretely in their functions. But if the differences in behavior of a Sword and an Axe are simply going to be determined by the values in a group of stats, things that are best treated as data containers for games, they should just be defined by parameters that all objects share.

If you're familiar with the MVC pattern, using multiple inheritance to make similar data containers is like creating a bunch of controllers that only differ in the values in its data members. Obviously it's better to just have one controller and rely on the model to fetch the values that are needed.

You didn't go in-depth as to what properties your classes have, but weapon inventory seems to benefit a lot more from a data-driven design. So have just one Weapon class and assign it different properties, and to name them, the name is simply a read-only string member.

If you want to have hybrid items (as the SwordWithCannon mentioned before), perhaps then define a Weapon class that can take properties of multiple Weapon objects, ie. in a Vector or List containing one or more sets of properties.

\$\endgroup\$

You must log in to answer this question.

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