How to implement an inventory system for a 2D game?

This is a discussion on How to implement an inventory system for a 2D game? within the Game Programming forums, part of the General Programming Boards category; Making my first game, a 2D RPG, using C++ and SFML for the graphics, and everything works so far, but ...

  1. #1
    Registered User
    Join Date
    May 2012
    Posts
    28

    How to implement an inventory system for a 2D game?

    Making my first game, a 2D RPG, using C++ and SFML for the graphics, and everything works so far, but I'm stuck now at the inventory system.

    I looked up linked lists, but I'm not sure how to actually implement that (with SFML) to get objects to show up in their correct positions on the screen, and how to interact with those objects, etc. It'd be great if there was a tutorial on making a 2D inventory system.

    I already defined X and Y coords for the positions of each item sprite (for when I display it). I've also made a few test images (all identical sized images). The buttons on screen work, but don't do anything so far.

    To restate, I don't know how to use a linked list to make an inventory system.

    Here are some examples (Screenshots (3) - Imgur) of what I have in the game so far. Pardon the Paint graphics; they're not place holders for future amazing graphics, I just suck at drawing and I'm okay with that since this is for fun.

    Thanks in advance for any help.

  2. #2
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,046
    Unfortunately I'm not familiar with SFML, but I'm very familiar with the SDL, and I'm assuming it's similar. The first thing to keep in mind: you may not want your internal representation of the inventory to be the same as the graphical representation.

    Here's what I mean. A linked list is just a data structure (the other most common one being a vector/dynamic array). It holds a list of elements; that's it. Maybe that's a good choice for representing the objects the player has in their inventory. However, when you're displaying the inventory you need to keep track of (e.g.) row and column positions and convert those into pixels and then actually display the objects' images. There's no reason the position-information has to be stored in the actual "inventory" list. You could auto-generate it. Pseudo-code:
    Code:
    row = 0, col = 0
    for each inventory item i:
        col ++
        if(col >= NUMBER_OF_COLUMNS) row ++, col = 0
        x = 100 + col*10  // or whatever. Convert to pixels
        y = 200 + row*10
        drawImage(image for object i, x, y)
    As for data structures themselves. Well, you could make your own linked list or vector if you wanted to, but you should be aware that the standard C++ library already has std::list (a linked list) and std::vector (a dynamic array)! Of the two, I suggest std::vector because it's easier to index elements in it -- and the efficiency differences don't matter if you have small data structures.
    Code:
    #include <vector>
    std::list<vector> data;
    data.push_back(1);
    data.push_back(2);
    data.push_back(3);
    for(int x = 0; x < int(data.size()); x ++) {
        std::cout << data[x] << std::endl;
    }
    If you have using namespace std you can drop my std:: prefixes. Notice that I casted data.size() to type int; its return value is actually of type std::vector<int>::size_type, which is unsigned, so you'll get signed/unsigned warnings if you have warnings enabled. (You do have warnings enabled, right? For g++: add -Wall -Wextra to your compiler options.) Basically if you care about the warning, you can cast the return value or use
    Code:
    for(std::vector<int>::size_type x = 0; x < data.size(); x ++)
    Quite a mouthful. Looks better with typedefs.

    If you really really wanted to, you could implement your own linked list. But seriously, there's no reason for it unless you specifically want to learn how linked lists work. That's useful in itself but if you just want the data structure for use somewhere else, it's *way* easier to use the builtin ones. There's always some bug you miss if you implement it yourself.

    I've talked about the data structure but haven't said anything about inventory items themselves. Obviously you probably won't want to use an int. The simplest possible solution is probably this:
    Code:
    enum ItemType {
        ITEM_SWORD,
        ITEM_MAGIC_KEY,
        // ...
    };
    
    struct InventoryItem {
        ItemType type;
        std::string imagePath;
    };
    
    std::vector<InventoryItem> inventory;
    InventoryItem sword;
    sword.type = ITEM_SWORD;
    sword.path = "sword.png";
    An enum is basically names for 0, 1, 2, etc. You can use a string if you prefer. If you want to make that more complicated you could use a class.

    Also, you may have noticed that the image-name to use is also display-information, which can be separated from the actual inventory objects themselves. So you could just have inventory objects contain a certain type, and then e.g. an array to map types to images...
    Code:
    std::string files[] = {
        "sword.png",
        "magickey.png",
        // ...
    };
    paint(files[ITEM_SWORD]);
    But I digress. In fact, I think I began digressing about ten percent of the way through this post. Anyway, hope some of it is useful.
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

  3. #3
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,046
    Sorry for the double post, I can't edit my previous one -- maybe it's too big?

    I just wanted to add that your graphics look pretty good. Better than I could do in Paint. Also, if you're comfortable with it, you should definitely post your game here when it's finished. Or when you want more feedback, because when are projects ever finished.... Cheers.
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

  4. #4
    Registered User
    Join Date
    May 2012
    Posts
    28
    Wow, thank you for the long, detailed post!
    I'll have to think how to incorporate what you wrote with SFML (SFML is nice, but it sometimes doesn't play well with others).
    As for the game, I'd gotten help on this forum prior for how to set-up a server and client (so that part is ready), so this game should be multiplayer over TCP/IP when it's "finished." I don't think it can ever be finished though, since each room takes at least 6 lines of code, and there are over 90 rooms per map grid, and I'd need at least 20 map grids. But once all the features work, I'll release the game with the source code to hopefully help someone else trying to work on the same thing.

  5. #5
    Registered User
    Join Date
    Jun 2011
    Posts
    2,238
    Quote Originally Posted by Pikmeir View Post
    ...I don't think it can ever be finished though, since each room takes at least 6 lines of code, and there are over 90 rooms per map grid, and I'd need at least 20 map grids...
    I don't know if this will be applicable to your program, but if most of the code for your rooms is similar (i.e. same commands with different variables), you might be able to speed up development through the clever use of spreadsheets.

    I just finished a small console game with "graphics" (using ASCII characters to define walls, objects, and the player). There are 14 rooms, each one a 30x30 grid. It appeared that it would take days to design, implement, and troubleshoot the code for all the rooms.

    But I was able to complete this in a matter of hours using MS Excel. For my application, I created a 30x30 grid in Excel and to the right of this, I typed in the skeleton "code." Then, I wrote formulas to generate actual code based on; (1) the skeleton code, and (2) the values I put into the main grid. I was then able to "color in" the grid to get a visual of the layout, then just add the appropriate data to each square in the grid. The code was "auto-generated" through the formulas, and I had all the code I needed for the room. I just copy+pasted this into my compiler.

    Then it was simply a matter of copying the sheet to make the next room, etc. And when I had to make changes to the rooms (which I did often during development), I just updated the data in the grid and re-copied the resulting lines of code.

    I understand your game is a lot more sophisticated graphically, and my specific example does not apply - but perhaps you might be able to apply these methods to help make your development easier.

  6. #6
    Super Moderator VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,590
    You do not need a linked list for inventory. Most inventory is composed of 'slots' and a set number of them which screams use an array or a pre-sized vector. A linked list would be awful b/c players can select any item from inventory at any time. If you need random access to the collection a std::list is not the container to use. Normally I would say use a vector of pre-set size but in this case a simple array of integers would work fine because the collection size is fixed. The integers would be the ID's of the objects which could be taken from a master list. Rendering is simple - render the object that has the specified ID at inventory slot x,y on the screen. Since inventory is usually a grid the math to do that is uber simple.

    Note that if your inventory collection can be random in size then a vector is the way to go. An inventory collection that could be random would be one where the max number of items was based on total weight of all the items. With that type of design you could carry a ton of little items or one big item depending on the total weight. This is how Skyrim and most other RPGs implement inventory systems. At any rate if you do not use integer IDs in your vector then use pointers to inventory items on the heap. If you have Skyrim note that you can press the console key '~' and point to any item which will show it's object ID. You can then use this ID to manipulate the item via console commands. Each object in the world has a unique ID which is quite nice b/c it means you can place all the objects in a hash table and get O(1) lookup which is more than likely what they are doing. Note that the object IDs in that game do not change from game to game or system to system.


    Moved to Game Programming.
    Last edited by VirtualAce; 07-05-2012 at 05:31 PM.

  7. #7
    Registered User
    Join Date
    May 2012
    Posts
    28
    Quote Originally Posted by Matticus View Post
    I don't know if this will be applicable to your program, but if most of the code for your rooms is similar (i.e. same commands with different variables), you might be able to speed up development through the clever use of spreadsheets.

    I just finished a small console game with "graphics" (using ASCII characters to define walls, objects, and the player). There are 14 rooms, each one a 30x30 grid. It appeared that it would take days to design, implement, and troubleshoot the code for all the rooms.

    But I was able to complete this in a matter of hours using MS Excel. For my application, I created a 30x30 grid in Excel and to the right of this, I typed in the skeleton "code." Then, I wrote formulas to generate actual code based on; (1) the skeleton code, and (2) the values I put into the main grid. I was then able to "color in" the grid to get a visual of the layout, then just add the appropriate data to each square in the grid. The code was "auto-generated" through the formulas, and I had all the code I needed for the room. I just copy+pasted this into my compiler.

    Then it was simply a matter of copying the sheet to make the next room, etc. And when I had to make changes to the rooms (which I did often during development), I just updated the data in the grid and re-copied the resulting lines of code.

    I understand your game is a lot more sophisticated graphically, and my specific example does not apply - but perhaps you might be able to apply these methods to help make your development easier.
    I thought about that (though I have no idea how I'd do that), but in the case of my game, my code is simple enough to just program it manually, rather than using a spreadsheet. Here's how my room code works. When the player presses one of the direction buttons on the screen (up/down/left/right), if an exit is available it adds or subtracts 1 to X or Y, and then runs this function for determining what to display on the screen, which in turns places the player sprite in the proper location for the room and sets the exits, etc.

    Code:
    void setStrings(std::string &str, std::string &str2, std::string &str3)
    { // if (iMapCode = 1); // add this later for extra maps
     if (Xpos == 1 && Ypos == 1) // if the player is at coords X 1 and Y 1
     {
      miniPlayerSpr.setPosition(164, 295); // the mini player sprite on the main game map
      str2 = "Leujor Town Hall."; // the name of the room
      str = "Before you is a yellowed, mud brick building at\nleast twenty men tall. Its windowless exterior\nis rather uninviting, and would be fearsome were it\nnot for the four, wide-open metal doors at the front\nof the building."; // description of room
      str3 = "Exit(s): Up, Right"; // Up to "Brick Building," Right to "Side alleyway." // description of exits
      bUpOk = 1; // it's OK to go up
      bRightOk = 1; // it's OK to go right
      bDownOk = 0; // it's not ok to go down
      bLeftOk = 0; // it's not ok to go left
     }
     else if (Xpos == 1 && Ypos == 2)
    ---etc etc do the same thing

  8. #8
    Registered User
    Join Date
    May 2012
    Posts
    28
    Quote Originally Posted by VirtualAce View Post
    You do not need a linked list for inventory. Most inventory is composed of 'slots' and a set number of them which screams use an array or a pre-sized vector. A linked list would be awful b/c players can select any item from inventory at any time. If you need random access to the collection a std::list is not the container to use. Normally I would say use a vector of pre-set size but in this case a simple array of integers would work fine because the collection size is fixed. The integers would be the ID's of the objects which could be taken from a master list. Rendering is simple - render the object that has the specified ID at inventory slot x,y on the screen. Since inventory is usually a grid the math to do that is uber simple.
    Any recommended tutorials for how I could learn how to use an array for my inventory system instead of a linked list? I've been able to find tutorials for everything except making inventory systems, it seems. If I can just use an array for this it might be a lot simpler for me.

  9. #9
    Super Moderator VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,590
    You do not need a tutorial on inventory systems. You need to read up on the various containers and data structures you can use given your knoweldge of the particular inventory system you want to implement. If you learn that then you can implement more than just an inventory system.

  10. #10
    Registered User
    Join Date
    May 2012
    Posts
    28
    Quote Originally Posted by VirtualAce View Post
    You do not need a tutorial on inventory systems. You need to read up on the various containers and data structures you can use given your knoweldge of the particular inventory system you want to implement. If you learn that then you can implement more than just an inventory system.
    Name:  WgXyX.png
Views: 1112
Size:  3.2 KB
    I'll go back to the tutorials on arrays and see if I can't learn something new this time. I'm still a beginner so maybe this is still above my head until I learn some more.

  11. #11
    Registered User
    Join Date
    May 2012
    Posts
    28
    Went ahead and re-read a few tutorials on arrays, and lo and behold something clicked. I think I've got a new idea that should work, so I'll implement it and give it a try. I think I can just stick with a standard array for this, and work around it. If anyone wants I can post the code I get for my inventory solution once it's done. If not I'll just post the whole game and source once the rest of the framework is all set up.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Need help on Electronic Inventory System...
    By beh007 in forum C Programming
    Replies: 1
    Last Post: 12-27-2011, 07:42 PM
  2. How should i make a inventory system for my text adventure?
    By Nathan the noob in forum Game Programming
    Replies: 7
    Last Post: 03-12-2010, 06:21 PM
  3. Inventory System
    By headshot119 in forum C Programming
    Replies: 28
    Last Post: 09-24-2009, 10:53 AM
  4. inventory system
    By linucksrox in forum Game Programming
    Replies: 0
    Last Post: 04-19-2006, 01:19 PM
  5. Thoughts on Menu System for Book Inventory
    By curlious in forum C++ Programming
    Replies: 3
    Last Post: 09-29-2003, 03:32 AM

Tags for this Thread


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21