4
\$\begingroup\$

I had a question regarding the best way to have items in my RPG game.

Currently I have a class structure in which everything inherits from GameObject. Item inherits GameObject. Armour Inherits Item. Helmet inherits Armour. Etc.

I am wondering whether I should have a class for each specific piece of armour, weapon, item, etc. in the game, or whether I should have generic "Helmet", "Shield" etc. classes and then use a factory instead to fill in the constructor arguments. I am unsure of whether the number of classes will become too much and if this is bad.

Classes:

Item* firstHelmet = new LeatherHelmet();
Item* otherHelmet = new SteelHelmet();

Factory:

Item* firstHelmet = Armour::Create(ArmourType.Helmet, Tier.Leather);
Item* secondHelmet = Armour::Create(ArmourType.Helmet, Tier.Steel);

The first example will result in a large number of classes. However, the second example is going to result in a lot of if statements or switch cases to query the type and tier of armour being created and then setting the appropriate variables.

Which is best, or is there another better solution I am missing?

\$\endgroup\$
5
\$\begingroup\$

The rule of thumb about whether to subclass or to create multiple instances of the same class is: Do these objects need different program logic or just different values?

When the steel helmet and leather helmet use the exact same programming and only differ by the values of attributes like name, defense, price and sprite, they should all be instances of the class Helmet.

When all types of armor use the same programming and differ only by which equipment slot they occupy, then they should all be instances of the class Armor with an attribute slot.

But if any armors have unique game mechanics, then it might make sense to implement these as individual sub-classes. When all helmets have values for hearing-impairment and vision-impairment but all other types of armor have not, then a class Helmet inheriting from Armor which has these additional attributes might make sense. When you have an unique helmet with a very gimmicky game mechanic, like a helmet which turns the character into a chicken if equipped on a Thursday, it might make sense to create an unique class just for this helmet which overrides the equip method. On the other hand, if you have many items with unique mechanics, it might be worth it to add a scripting engine to your game and allow items to contain scripts.

the second example is going to result in a lot of if statements or switch cases to query the type and tier of armour being created and then setting the appropriate variables.

Instead of hardcoding your item creation you might want to consider to move your items and all of their values to an external file. You will still have a switch to convert strings from the file to the correct enumerations, but all the numeric values should come directly from the input file.

This keeps your item initialization code clearer and also gives you the advantage that your can change your item values without having to recompile the game.

| improve this answer | |
\$\endgroup\$
  • 6
    \$\begingroup\$ When you start getting into very quirky item behaviours, I'd be tempted to move toward a component-based system. So the helmet that turns you into a chicken and the gauntlet that turns you into a snake and the sword that turns you into a swordfish can all have a Transmogrification component attached, rather than needing to re-implement that functionality in multiple different item class lineages. ;) \$\endgroup\$ – DMGregory May 23 '18 at 12:35
2
\$\begingroup\$

There is probably not the one ultimate solution. In our game we are basically using your second approach:

All our items inherit from a base Item-Class that sums up all properties that they have in common. Like if they can be sold, and if then their sell value or if they are magic or not.

The items themself are divided by their purpose. So we have classes for wearables (which have a property on what slot they can be equipped [chest, feet ...]) weapons, consumeables (food, potions...) and materials (mainly for crafting or misc. stuff like Wood or an old can) Last but not least we have a seperate class for quest items since those may have unique use-effects or properties.

By now we store all our items in an XML file and parse the items from there into the game. Since there is not such a massive amount of items like in current MMOs we tend not to use a seperate database or something.

By now we are quite satisfied with this system. But Keep in mind that you may need to adapt your structure during you dev progression and on how many different items you plan to implement.

| improve this answer | |
\$\endgroup\$
0
\$\begingroup\$

If you think about it logically, in terms of behaviour:

Armour protects are part of the body(slot). In an rpg it will negate a certain amount of damage, which depends on it's class (cloth/leather/mail/plate whathaveyou). This is not a change in behaviour, this is simply a change in values.

Likewise:

A weapon deals damage. How fast it deals it, and how much it deals, is down to it's weapon class. Again, no change in behaviour, just numbers.

Here's where it gets confusing: How do I deal with Bows/guns etc? Well, you introduce a "attack range" value. This value is the max distance the character can be from an enemy before this weapon can be used. Ranged weapons have this number set to a far larger value than the melee weapons.

The only behaviour that may differ is special effects, or "magic" armour and weapons, such as defensive effects that are passive, or trigger when hit, and weapon effects that trigger when they hit something.

Diablo 3 uses a very simple method to do all this:

It generates a weapon within a specific level range. This dictates the outside range of min/max damage it can deal. A quality level is randomly generated, which upgrades the damage numbers again, and dictates how many "prefixes" and "suffixes" the item can have.

For each such affix, additional damage/defence values may be added to the base, or other numbers may be added, such as resistances, triggered effects, elemental modifiers etc.

So, rather than seeing a bad/decent/good/excellent weapon as different classes, we say that any weapon can have excellent values, but will likely not. Just as legendary weapons can have on hit effects (represented by, perhaps, plugin callback classes), but other weapons do not.

The behaviour of the items itself does not change, only the values of the item. Remember that what you see, animated on the screen, is not necessarily what is going on in behind the scenes.

But this is just how the Diablo series does it (And how I would do it, if so inclined). You may find that a polymorphic approach works for you.

| improve this answer | |
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.