The items are stored in a std::unordered_map<std::string, std::pair<std::unique_ptr<Item>, unsigned>>;
I will break down why I chose for this. First of all, I wanted the items to be accessible in some way. Iterators were clumsy, because they would invalidate when an item is added to the inventory. I still kept the begin() and end() functions for if you would want to iterate through an inventory in a loop. So I chose for an undoredered map, with string indices so you can give every item it'sits own string ID. The items are stored as a pair of [Item, Count], since I wanted to be able to stack items where possible (Item.stackable() == true
).
The items are stored in a std::unordered_map<std::string, std::pair<std::unique_ptr<Item>, unsigned>>;
I will break down why I chose for this. First of all, I wanted the items to be accessible in some way. Iterators were clumsy, because they would invalidate when an item is added to the inventory. I still kept the begin() and end() functions for if you would want to iterate through an inventory in a loop. So I chose for an undoredered map, with string indices so you can give every item it's own string ID. The items are stored as a pair of [Item, Count], since I wanted to be able to stack items where possible (Item.stackable() == true
).
The items are stored in a std::unordered_map<std::string, std::pair<std::unique_ptr<Item>, unsigned>>;
I will break down why I chose for this. First of all, I wanted the items to be accessible in some way. Iterators were clumsy, because they would invalidate when an item is added to the inventory. I still kept the begin() and end() functions for if you would want to iterate through an inventory in a loop. So I chose for an undoredered map, with string indices so you can give every item its own string ID. The items are stored as a pair of [Item, Count], since I wanted to be able to stack items where possible (Item.stackable() == true
).
EDIT: as per request in the comments, here are some further explanations:
Architecture
As I created this project with portability across other projects in mind, so as a kind of library, the architecture is designed to be as simple to use as possible. All Items will be inherited from a base IItem class, or any other class that supports the functions in the Inventory::Traits class. The inventory is responsible for managing the resources of every item, and for creating them. So when adding an item you call
inventory.emplaceItem<SomePotion>("Potion", 50); //the 50 is passed to SomePotion's constructor
MAX_SIZE
MAX_SIZE is a template parameter due to an unlucky design choice at the very beginning. Since I did not want to do lots of allocations for items, I wanted to have the size fixed. This is probably completely unneccesary, but annoying to remove now.
Item usage
Since the Inventory is responsible for using the items (by calling useItem("name", target_ptr);
), I needed some way of doing that. I chose for the Visitor Pattern, which I implemented with the ItemDispatcher
class.
Data Structure
The items are stored in a std::unordered_map<std::string, std::pair<std::unique_ptr<Item>, unsigned>>;
I will break down why I chose for this. First of all, I wanted the items to be accessible in some way. Iterators were clumsy, because they would invalidate when an item is added to the inventory. I still kept the begin() and end() functions for if you would want to iterate through an inventory in a loop. So I chose for an undoredered map, with string indices so you can give every item it's own string ID. The items are stored as a pair of [Item, Count], since I wanted to be able to stack items where possible (Item.stackable() == true
).
Reusability
About the reusable in multiple projects. With that I mean that if I, at some point decide to make an RPG game, and the character needs an inventory, that I can just use this exact Inventory class without any modifications. If I then later want to make another, completely different game that also features an Inventory, or some other way of storing items, I can reuse this again.
Techniques
The Traits class is used as a wrapper for the SFINAE type traits that I use to detect if an eventual custom Item type supports all required functions, set for example like:
Inventory<200, MyCoolGameObject, MyCoolItem> inventory;
Traits is a class because I can't do
class X
{
namespace Y
{
};
};
EDIT: as per request in the comments, here are some further explanations:
Architecture
As I created this project with portability across other projects in mind, so as a kind of library, the architecture is designed to be as simple to use as possible. All Items will be inherited from a base IItem class, or any other class that supports the functions in the Inventory::Traits class. The inventory is responsible for managing the resources of every item, and for creating them. So when adding an item you call
inventory.emplaceItem<SomePotion>("Potion", 50); //the 50 is passed to SomePotion's constructor
MAX_SIZE
MAX_SIZE is a template parameter due to an unlucky design choice at the very beginning. Since I did not want to do lots of allocations for items, I wanted to have the size fixed. This is probably completely unneccesary, but annoying to remove now.
Item usage
Since the Inventory is responsible for using the items (by calling useItem("name", target_ptr);
), I needed some way of doing that. I chose for the Visitor Pattern, which I implemented with the ItemDispatcher
class.
Data Structure
The items are stored in a std::unordered_map<std::string, std::pair<std::unique_ptr<Item>, unsigned>>;
I will break down why I chose for this. First of all, I wanted the items to be accessible in some way. Iterators were clumsy, because they would invalidate when an item is added to the inventory. I still kept the begin() and end() functions for if you would want to iterate through an inventory in a loop. So I chose for an undoredered map, with string indices so you can give every item it's own string ID. The items are stored as a pair of [Item, Count], since I wanted to be able to stack items where possible (Item.stackable() == true
).
Reusability
About the reusable in multiple projects. With that I mean that if I, at some point decide to make an RPG game, and the character needs an inventory, that I can just use this exact Inventory class without any modifications. If I then later want to make another, completely different game that also features an Inventory, or some other way of storing items, I can reuse this again.
Techniques
The Traits class is used as a wrapper for the SFINAE type traits that I use to detect if an eventual custom Item type supports all required functions, set for example like:
Inventory<200, MyCoolGameObject, MyCoolItem> inventory;
Traits is a class because I can't do
class X
{
namespace Y
{
};
};
Note: I have just read a meta post that says that it is not allowed to post GitHub links. I am not sure what I should do in this case, as I mostly want the Inventory header reviewed. The files in the github repo are only for when there really is more information required.
Note: I have just read a meta post that says that it is not allowed to post GitHub links. I am not sure what I should do in this case, as I mostly want the Inventory header reviewed. The files in the github repo are only for when there really is more information required.