Using classes for items

Started by
11 comments, last by Ravyne 13 years, 9 months ago
I'm messing around with this little game here and I'm at the point where I can implement some sort of inventory system and item management with like weapons and story items, bla bla. Being a student in programming I can't say I have worked with objects/classes enough to understand how well to use them yet.

I was wondering if the way I am structuring my item types is a good way to do this. At the root I have a "clsItem" which is any item at all. Then inherited from clsItem are clsStaves, clsSwords and clsDaggers, those are the weapon types. I also have to create base classes for the chestpieces, legs, hands. And then there comes the usables like potions and the like. But when I look at it, that makes a lot of classes... And perhaps this "inheritance tree" is not a good way to do this.

Any suggestions on how I could better structure my classes ? My program is starting to be a mess and I'm getting a bit lost. I'd even take a book recommendation that talks about the subject.


Addendum: one might say that I should simply wait until I get classes on the subject at school but its summer and I want to go forward, not wait idling behind.
Advertisement
I find that basing all game objects off a inheritance tree works fairly well but works a lot better in a language with high level object management and reflection like python, action script 3, java or C#.
In my opinion, I think using a class hierarchy for every possible item type is overkill especially considering that items of a given type don't exhibit wildly different behavior that requires extensive coding.

My preferred approach would be to use tags e.g. WEAPON, STAFF, SWORD, DAGGER, TWO-HANDED, ARMOR, GLOVES, etc...

Your main item class would contain a classification field implemented as a set. Item types i.e. tags would be implemented an enumeration. If you have limited space then you can limited the number of tags that this set can contain to a number such as 5.

Then a pair of magic leather gloves would have the tags: MAGIC, GLOVES, LEATHER. A silver bastard sword might be WEAPON SWORD TWO-HANDED SILVER. Your source code would then be written to handle certain tags e.g. only a SILVER WEAPON can damage a vampire.

Save your class hierarchy for items that have radically different behavior. E.g. clsItem, clsWeapon, clsArmor, clsPotion, etc.

From a programming point of view, most weapons are treated the same--they can be wielded to do melee damage to a mobile. Likewise most armor is alike and same with potions. For a further foray into programming concepts you might also want to investigate composition over inheritance.
Quote:Original post by loom_weaver
In my opinion, I think using a class hierarchy for every possible item type is overkill especially considering that items of a given type don't exhibit wildly different behavior that requires extensive coding.


That entirely depends on what type of game your making though for a standard rpg Weapon(string type,int weight,int hit,int damage) would work well.
I don't think you need to separate a staff from a sword in code. You can add a byte that indicates the ID of the animation to use, then have all weapons use that same class.

Using inheritance for items is a good exercise of object-oriented programming, but I find it annoying to program in practice in an actual game, due to the existence of the hidden __vtable class member that is automatically created for all classes using virtual functions. That forces me to either avoid all virtual functions, or to save and load my items member-by-member, which is obviously very error-prone and decuplates the length of my saving and loading routines. I prefer to use simple structures: since all members have the same size and there's no read-only members like __vtable, you can save and load your whole array of items in one block, and you can keep all your items in one simple array instead of using a list of pointers that you have to delete later. Long story short, you spend less time coding and debugging.

For my RPG, I handle this issue with unions. I don't know if unions are considered good programming practice, but I found it simpler to store my item data in one same structure, and to use an union of sub-structures to store all type-specific data, such as attack power if it's a weapon, or healing if it's a potion. You could use normal structures, but you would end up allocating tons of useless variables, like an attack power stat to a potion. Unions are like structures, except that all its data members share the same address in memory, so you don't end up allocating space for health recovery if an item isn't a potion. You use a header that stores all common data such as name, description and price, then you add a control byte that tells your game what kind of item it is, and that your game uses to figure which member of the union contains is the right one.

In C++, it would look like this:
struct ITEM{    char szName[ 32 ];    char szDescription[ 128 ];    int nPrice;    int nTypeId; // 0 = WPN; 1 = ARMOR; 2 = HELM; ...    // then you have the content-specific structure    union    {        struct WEAPON_TYPE        {            int nAttack;            int nHitChance;            int nElement;            int nAnimationId;            // add other weapon specific stuff here...        } Weapon;        struct ARMOR_TYPE        {            int nArmorClass;            int nEvasion;            int nFireResistance;            int nFrostResistance;            int nShadowResistance;            // add other armor specific stuff here...        } Armor, Helm, Shield, Accessory; // since all protective gear share the same                                          // data, they all use the same bytes.        struct POTION_TYPE        {            int nHealthRecovery;            int nManaRecovery;            bool bCuresDeath;        } Potion;    } Content;};


Then your game determines what kind of item it is by reading the ITEM::nTypeId member, and read to the right structure accordingly:
#define WEAPONCLASS_WEAPON     0#define WEAPONCLASS_ARMOR      1// is it a weapon?if( Item.nTypeId == WEAPONCLASS_WEAPON )    int nAttack = Item.Content.Weapon.nAttack; // read the content as a weapon// is it a piece of armor?else if( Item.nTypeId == WEAPONCLASS_ARMOR )    int nArmor = Item.Content.Armor.nArmorClass; // read the content as an armor//// TODO: More code...//

I find that method easier to handle then inheritance and run-time type checking. Of course, that means that if you read the wrong type of content of the union, say a potion as a weapon, then you will read random and most likely incorrect values, so you need to validate the item type with ITEM::nTypeId before reading its content unless you're 100% sure that it's always the correct type.

I'm sure there are other ways to do this, but this was the one that worked best for me.
I have just a couple of quick questions you should think about.

1) When you say weapons I assume you mean the data structure that defines the stats. You are separating your game logic from your rendering logic I hope. If so, you need to also try your best to separate your game data from your game logic as well.

Data should be something you can read out of an .ini file or some similar flatfile system.

Having said that, and this isn't specifically to your point so my apologies, but the most important thing is to not let it be a roadblock.

Chunk them all together in a kitchen sink class and get it working in-game, you can worry about refactoring it later if it becomes a problem, and when you get there you'll know more about the system it lives in and its' shortcomings.

Right now you can only guess.


Here is a link to a really interesting article on how they did the last Rachet and Clank. It's overkill in all likely hood but it is based on the truism, "favor composition over inheritance" which some is bound to jump in to this thread and tell you about eventually.
"Let Us Now Try Liberty"-- Frederick Bastiat
Thanks for all the answers ! Great info, I will try to use those tags since they look like a lot less work making classes over and over again.
Quote:Original post by Bearhugger
......

This is a workable solution for c or c++ but if your using a higher level language you might want to look into automatic serialization and the "as" operator.


Quote:Original post by Kratosaurion7
Thanks for all the answers ! Great info, I will try to use those tags since they look like a lot less work making classes over and over again.


I would use a combination of classes and tags. If your just making a text based rpg just tags are fine but for larger project dividing up the code into logical segments is a good thing and having too many classes usually not a problem.
Quote:I would use a combination of classes and tags. If your just making a text based rpg just tags are fine but for larger project dividing up the code into logical segments is a good thing and having too many classes usually not a problem.


Yeah thats what I'm thinking. The way I'm probably going to follow is that I will have the root class, which is inherited from the couple of sub-types of item I will be using: Weapon/Armor/Usables/Quest-Items/Keys etc. And each sub-sub-type will be differentiated by tags. Like: Root->Weapon->InstanceName="Iron Sword" Tags="Sword","Iron" Damage="15" .

Kind of like that ? Its a simple example and I might go into more details and need more classes but I'm still deciding what way to go.

Edit: Is there a VB.net equivalent of a C++ union ? I could also look into that if need be.
Quote:Original post by Kratosaurion7
Edit: Is there a VB.net equivalent of a C++ union ? I could also look into that if need be.


If your using .Net you probably want to use classes where Bearhugger used unions or structs. In c++ structs are simplified objects, in .Net structs are stack allocated data structures.

This topic is closed to new replies.

Advertisement