3 Answers
3

The same way you design any inheritance structure: You think about what all weapons, without exception, have in common. Obviously, damage comes to mind. Attack rate. Remember that you don't have to (and should not!) cramp everything into the base class. You put into a class what you need it (and all child classes) to do, no more and no less.

Next step, you could make 2 classes, MeleeWeapon and RangedWeapon, which both inherit from Weapon. Maybe that split is necessary because a MeleeWeapon has no range, and/or only a RangedWeapon uses ammunition. Then you repeat the above process for each of those classes, until you have all classes you need.

At every branch, you should also consider if you really need to split into 2 or more classes. For example, melee weapons could also have a meaningful range, such as spear vs. dagger, or your ranged weapons could have infinite ammo. That totally depends on your game design and cannot be generalized.

Thank you very much, I have some quick drafts for some classes now :)
–
meth0d_Sep 14 '11 at 15:14

8

-1, while your first paragraph I agree with, the rest of your answer trends towards the very outmoded and out-of-favor inheritance-heavy approach to design.
–
Josh Petrie♦Sep 14 '11 at 15:24

1

Just want to add that every weapon has a range. If a melee weapon would have a range of less or equal 0 it would not hit anything!
–
MarcoSep 14 '11 at 16:13

1

@Marco An example where 0 range works: In a grid based system, the range represents how many squares away the target can be. 0 squares away is adjacent. 1 square away is any adjacent to the adjacent squares, and etc. What "0" means is a design specific question, and can be a valid value for range.
–
normanthesquidSep 14 '11 at 17:39

1

@normanthesquid yes, I see, special cases. To Hackworth: It's not off-topic, since you were giving a statement in your answer and I thought that it would not be right; That's the matter with comments. Anyways, I still think that a range has to be defined (0 is also a value) to check any collisions with any entity. However, my understanding of range might actually differ from yours, so we should just stop discussing here.
–
MarcoSep 14 '11 at 18:18

To add to Hackworth's answer, with regard to damage and attack rate, in an RPG there are also modifiers to abilities. A heavy weapon may actually reduce your strength or dexterity, and give you negative modifiers. However, instead of thinking about having all weapons inheriting your modifiers, create a Modifier interface and implementation that has getters/setters for those modifiers. Now your Weapon interface should have a getter/setter for your Modifier object. This favors composition over inheritance when it makes sense.

It should certainly be possible to create a single class that represents all weapons equally well -- and this is ideal, because allowing yourself to fall into the trap of creating many subclasses for each weapon type is cumbersome. Composition(*) should be favored over inheritance.

The big challenges are going to be

Enumerating the set of data and behavior that you expect of all classifications of weapon.

Determining how to abstract that data and behavior into a data-oriented approach.

"Range" is a good example -- both swords and guns both have a range. You can either elect to use a simple system when a range of 0 just means "melee" or you can use a real-world measurement so as to (as suggested by another poster), gives daggers a shorter reach than a polearm.

Behavior can be handled by scripting(**). You could have an "on-activated" script object that was invoked when the weapon was used or swung -- the script for a melee weapon would look at the range, and the location of the actor using the weapon and perhaps compute the set of targets in an semi-circle in front of the actor and apply damage to each. Conversely the script for a gun might do a raycast from the actor, limited by the range.

(*) This does not strictly imply that you have to rely on "component oriented" systems to effectively avoid going crazy with inheritance.

(**) Either via scripts loaded from another language, like Lua, or by pointing the weapon at a C++ "Script" class which you do create subclasses of. The latter is obviously easier, but lacks some of the benefits of a scripting system as it requires recompilation, for example.