So I am playing a game called Factorio and I have a bunch of storage chests for items and it got me wondering how that's implemented. My guess is there's a storage class or something like that and 1 storage chest is Instantiated so I can have multiple of the same storage container but they all contain different items. How would I go about that?
A few guesses from myself would be to store the Storage Chests in a vector and add a new one to the vector each time I create a new one, or use a smart pointer and allocate a new one on the heap for each instance?
Here's what I have so far, I just put something quick together to quickly test.
Your code looks OK except for a couple of nit picking things :+) So, well done !!
I guess your code was to demonstrate multiple containers, so that might be the reason some of these things aren't in your code.
The Item class could be a struct, because:
1. There is a get and set function for the member variable;
2. Item is part of a private vector in the container, so there are no access worries (it's encapsulated in the vector);
3. There is no invariant. An invariant is a condition that must be upheld at all times. Prefer to use a simple public struct when there are no invariants, and a normal class with private variables when there is an invariant.
The Container class does have an invariant: maxStorageSlots There should be error checking on that - what if it is negative or some huge number? Presumably it should be less for the standard container and larger for the large container.
The Container class does not make use of the maxStorageSlots value. The ctor could use the reserve function to make sure the vector has maxStorageSlots places reserved.
One could write an ostream<< function to output the values in the Container.
One more thing ! Super pedantic, defensive programming ;+)
seeplus wrote:
Also mMaxStorageSlots could be of type size_t as it will never be < 0 (hopefully!)
Here's something I do in this situation:
1 2 3 4 5 6 7 8
void f(std::size_t a) {
std::cout << "a is " << a << "\n";
}
int z = -1; // bad, should have been std::size_t
//oops
f({z}); // compiler warns about narrowing because of brace initialisation
Another way of doing things:
Create a Validation class which is privately inherited into the class in question. The class ctor calls functions from the Validation class to verify that all values are within appropriate ranges and are ok. These functions can also be called to enforce invariants every time a value is initialised, changed, and when values are returned. There is a boost contract programming library, to help with this:
Thanks for the input, thats stuff I didnt know so thats a plus, as for the Item class, I just made something simple. If I were to fully flesh it out then It would be a full blown class, I could have made it a struct but if this were a real program it would have been a class.
But what I needed help with is if lets say I had a container class and needed multiple instances of one type of the same container type, lets say in this game the player makes 3 Standard Containers, how do I make it so that when the player places all three down that when they place something in one container, it doesnt show up in the other two? so each container is instanced and doesnt share its contents?
In my OP I can have multiple containers, but those are hard coded, in factorio, you can make as many chests as you want, would I use a pointer and/or a vector to create instances at runtime? Or maybe push back a chest to the heap?
if you have a 'box' class, and a container (heh...) of those (like a vector) each with its own internal container (like vector) of thingys, they are distinct by nature if you did not do something to make them share storage (like a static keyword, or a pointer to passed in memory).
if you want both (a magic game chest that every town you go into, it has the same items) and a normal chest (has its own inventory, no other chest can access it) then you have options ... do you ever need to do both?
yes, a container (vector) of your 'box' objects is what you need from the sound of it.
The issue is whether a Chest is a view to data (Inventory). There could be multiple views (Chests) to same data, in which case they all show the same thing (Items).
The nature of the Chest can thus dictate what a "put into Chest" actually does.
Note though that even if each Chest is separate, with its own unique inventory, there is still possiblity to see same items via multiple chests, if you don't actually put items (data) in them, but just views to items.
A pointer is more or less a "view". Kind of. Depends on how you use it.
In my OP I can have multiple containers, but those are hard coded, in factorio, you can make as many chests as you want, would I use a pointer and/or a vector to create instances at runtime? Or maybe push back a chest to the heap?
Well, the Factorio map is a grid, so most likely it looks something like
class Item{
public:
virtual ~Item(){};
virtualconst std::string &name() = 0;
//Other pure virtual functions...
};
class Chest : public Item{
protected:
//IIRC chests are Diablo-like inventories, but this is good enough for this example.
std::vector<std::unique_ptr<Item>> contents;
};
typedef std::pair<int, int> Location;
class Map{
std::map<Location, std::unique_ptr<Item>> placed_items;
public:
bool place_item(const Location &l, std::unique_ptr<Item> &item){
auto &previous = this->placed_items[l];
if (previous)
//Can't place two items in the same cell.
returnfalse;
previous = std::move(item);
returntrue;
}
};
int main(){
//initialization
//game loop:
while (true){
handle_events();
update_state();
draw();
}
}
void handle_events(){
while (!event_queue.empty()){
auto event = event_queue.pop();
//...
if (event.is_mouse_release()){
if (player_is_dragging_item() && event.is_on_map()){
Location loc = event.get_map_location();
std::unique_ptr<Item> &item = player.inventory.get_item_being_dragged();
if (!map.place_item(loc, item)){
//Show the player an error.
}
//Otherwise the std::move() removed the item from the inventory already.
}
}
}
}
As for where the instances originally come from, IIRC the player has to give a craft command that creates them somwhere in the inventory, that might look like