1
\$\begingroup\$

I'm working on a inventory system for a rpg. I want to be able to compare items, restrict access for specific items(i.e. consumables) for specific inventory slots(i.e. leg, head), summarize items based on their attributes and make it easy to introduce new types of items.

What is a good structure to manage these requirements?

I tried the following, but I have my doubts about it (I shorten it, to make it more readable):

class Attributes{
    public:
        int agility = 0;
};

class Stackable{};

class Inventoryable : Entity{
    public:
        string name = "";
};

class Wearable : Itemable, Attributes{};
class Consumable : Itemable, Stackable{};
class Armor : Wearable{};
class Weapon : Wearable{};
class Cloth : Armor{};
class Pike : Weapon{};

class Item : Inventoryable{
    private: 
        Inventoryable inv_;
    public:
        Item(Inventoryable inv_type) : inv_(inv_type) {};
}

int main(void) {
    Item socks = new Item(Cloth);
    socks.name = "Stinky Socks"; //Inventoryable
    socks.agility = 10; //Attributes
}
\$\endgroup\$
  • \$\begingroup\$ What doubts? Why do you think this is not a good approach? Also, you should tell us more about your use case (i.e. what kind of game are you working on, what requirements are there for the items etc.). \$\endgroup\$ – Ben Steffan Oct 26 '17 at 15:26
  • \$\begingroup\$ I'm worrying that I might run into problems later on(i.e. the diamond problem) if I'm going to pursue this concept. Before I begin to fill these classes I wanted to find out, if there is a possible better solution or if there are already any design flaws with my concept. I edited my post to include some requirements like you asked. \$\endgroup\$ – Durrahan Oct 26 '17 at 15:39
  • \$\begingroup\$ There is a solution (or at least, a mitigation technique) to the diamond problem which is called virtual inheritance in C++. \$\endgroup\$ – Ben Steffan Oct 26 '17 at 15:43
1
\$\begingroup\$

Depending on how many types of items you will have and how many items will be live at any one time it may pay to use the flyweight pattern. Where each item stack has a pointer to an item type which holds all the behavior, and hold the data that makes the stack unique and/or is used very often (how many items in the stack, id for the sprite to draw, ...).

Making the ItemStack objects fixed size (with a pointer when the you need that extra storage space) will let you make an inventory hold a std::vector<ItemStack> instead of a std::vector<std::unique_ptr<ItemStack>>. The first will have much better performance when iterating over all items in an inventory. Hold by value what you can and use as few pointers as possible for the rest.

I'm not a fan of complex inheritance trees, either you need a virtual function in the base class anyway or you need dynamic_casts all over the place.

Stackable as a tag type is a pretty bad way of making something stackable. You will need to dynamic_cast to find out whether it can stack and the stackable items may each have a different max stacksize that you then need to query. So just create a single virtual size_t get_max_stack() in the base class of the item type.

\$\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.