Thread: Tracking item location in inventory

  1. #1
    (?<!re)tired Mario F.'s Avatar
    Join Date
    May 2006
    Location
    Ireland
    Posts
    8,446

    Tracking item location in inventory

    I'm wanting to know where each object is located in the player inventory. And I'm having troubles deciding on the best way to do this, with my current class structure.

    Items are managed by CItem, a base class of an hierarchy that spawns CWeapon, CArmor, CPotion, CKey, CFood and CContainer (bags, chests, ...) . CItem is not abstract. Objects of CItem type are possible. These are usually non magical items that only serve as game plot objects, or simple trinkets.

    CInventory manages the inventory. This is a lone class.

    A player inventory is the sum of it's bodyparts plus a minimum of 15 objects it can carry around (and that I'm calling pool). Bodyparts are the typical RPG style. Head, Neck, Arms, Waist, Right Hand, Left Hand,...

    But the problem is the following. CInventory is meant to have wear() and unwear() member functions. When a player picks an item it gets moved to the pool. When he wears it, that object gets tagged as being worn on a specific bodypart. I don't really feel the need to remove it from the pool... just to tag it is being worn somewhere.

    I'm trying to avoid having a CInventory data member for every body part. And I'm also trying to avoid doing this on the CItem by adding a member specifying if the object is being worn anywhere (or nowhere at all). I feel this should be exclusively managed by CInventory. But I'm not sure how to achieve this. Since I'm using weak pointers, a simple vector is not doable.

    Code:
    class CInventory {
    public:
        CInventory(boost::shared_ptr<CCreature>);
        ~CInventory() {};
    
        void add(boost::shared_ptr<CItem>);
        void remove(boost::shared_ptr<CItem>);
        void equip(boost::shared_ptr<CItem>, BODYPART); // BODYPART is an enum
        void unequip(boost::shared_ptr<CItem>);
        void swap(boost::shared_ptr<CItem>, boost::shared_ptr<CItem>);
    
        int ContentsWeight() const;
    
    private:
        std::set<boost::weak_ptr<CItem> > contents_;    // inventory full contents
        std::bitset<NUM_BODY_PARTS>       use_;      // just a a quick way to check usage
        boost::weak_ptr<CCreature>        owner_;    // the owner of the inventory
        int                               maxweight_;
    };
    Last edited by Mario F.; 08-01-2006 at 04:50 PM.
    Originally Posted by brewbuck:
    Reimplementing a large system in another language to get a 25% performance boost is nonsense. It would be cheaper to just get a computer which is 25% faster.

  2. #2
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    Make a function that tests a given location to see if it's occupied. You could also do something like:
    Code:
    if( inventory.isused( myobject.getwearlocation() )
        inventory.wear( myobject );

    Quzah.
    Hope is the first step on the road to disappointment.

  3. #3
    (?<!re)tired Mario F.'s Avatar
    Join Date
    May 2006
    Location
    Ireland
    Posts
    8,446
    So you suggest I make the wear location a property of the object?

    I was trying to avoid it on the basis that I wanted to contain inventory operations inside CInventory. But maybe this is best.
    Originally Posted by brewbuck:
    Reimplementing a large system in another language to get a 25% performance boost is nonsense. It would be cheaper to just get a computer which is 25% faster.

  4. #4
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    Well it depends I suppose. An item is wearable or not, the object itself decides it. Or, a wear location is really just a container that contains specific types of objects. In which case, an "inventory" would be a list of containers. So the inventory, to see if it can hold any given item, would need to loop through all of the containers in the list, and compare what it's trying to store, with each object's "i can store this stuff" list.

    That's probably the better method, though it is more overhead in terms of lookup speed than checking the object itself to see if it can be worn.


    Quzah.
    Last edited by quzah; 08-01-2006 at 06:31 PM. Reason: typo
    Hope is the first step on the road to disappointment.

  5. #5
    (?<!re)tired Mario F.'s Avatar
    Join Date
    May 2006
    Location
    Ireland
    Posts
    8,446
    Thanks quzah.
    Originally Posted by brewbuck:
    Reimplementing a large system in another language to get a 25% performance boost is nonsense. It would be cheaper to just get a computer which is 25% faster.

  6. #6
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    Several approaches:

    1. Define base object and derive to gain more functionality
    2. Use a common 'properties' structure that applies to all objects.
    3. Define booleans for wearable and a value to indicate where it is worn.

    For #3.
    Code:
    #define HEAD 0x0001
    #define TORSO 0x0002
    #define ARM 0x0004
    #define HAND 0x0006
    etc.,etc
    4. Have smaller containers indicating what is being worn and where.

    For #4
    Code:
    std::vector<DWORD> m_vHeadObjectIDs;
    std::vector<DWORD> m_vTorsoObjectIDs;
    etc, etc.
    I do not like the approach of having CInventory actually handle items. Relegate that to an object manager and then CInventory would use the ID's to map ID to object via the object manager.

    Your manager classes should handle all of the objects. Everyone else is a 'client' of the managers and thus is never allowed to directly touch the object. The objects are out there for everyone to 'use' but not own. Your manager classes sort of act like object servers.

    A good example is an animation object. In any one game you may have 10 to 20 explosions occuring at the same time. Instead of loading the textures for each explosion, thus 10 or 20 instances of each frame, use object ID's. So the animations are just tools that anyone can use at any time any where. 1 instance of the animation and frames that compose it, and several instances of Sprites that use the 1 instance of animation. The Sprite class would control where the animation was relative to the screen.

  7. #7
    (?<!re)tired Mario F.'s Avatar
    Join Date
    May 2006
    Location
    Ireland
    Posts
    8,446
    I managed (3) with an enum actually, defined as such:

    Code:
    enum BODYPART {
        Head,           // 0
        Neck,           // 1
        Left_Arm,       // 2
        Right_Arm,      // 3
        Left_Hand,      // 4
        Right_Hand,     // 5
        Hands,          // 6
        Body,           // 7
        Waist,          // 8
        Legs,           // 9
        Feet,           // 10
        Left_Finger,    // 11
        Right_Finger,   // 12
        Container,      // 13
        Inventory,      // 14
        NUM_BODY_PARTS  // = 15
    };
    Your (1) is my weakness. I have trouble defining base abstract classes. Not that I don't understand the concept or can't actually code them. But more than I do have trouble doing it the right way. Definitely I need to read more about data structures and design patterns to better understand the advantages of abstract classes.

    Your (2) is great! Didn't think about it. Thanks for the tip I'm assuming you would want this implemented as a class that I could then use as a member of the base object?

    Ok... now... (4).
    I don't like it. Sorry
    I did think of it, but managing those many members seems repetitive and maybe unecessary. I've been giving this some more thought after Qzah's, and came up with something like:

    Code:
    map<CItem weak_ptr, BODYPART> contents_;
    Any changes to the enum would be replicated by this container without the need to change the code (much). This container would reflect a couple important properties in a much simpler way, i reckon:

    . Items cannot be replicated inside the container
    . Each item in the inventory is associated with a body location (with the extra pool being location 14-Inventory)

    As for the rest of your post, I do want to do it like you suggest. Or at least get close enough. I've been reading about your paradigm; Mngr and client classes. Both in C++ Primer and the recently bought Addison Wesley's Design Patterns Explained. I'm still shaky in my confidence in using these methods. But I will definitely use them. This project of mine, more than a need to have a final working game, is about learning how to correctly program in C++.
    Originally Posted by brewbuck:
    Reimplementing a large system in another language to get a 25% performance boost is nonsense. It would be cheaper to just get a computer which is 25% faster.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Immediate programming help! Please!
    By xMEGANx in forum C++ Programming
    Replies: 6
    Last Post: 02-20-2008, 12:52 PM
  2. Retail Outlet Managment System - the 4th
    By Presidentofusa in forum C Programming
    Replies: 3
    Last Post: 11-10-2007, 10:44 PM
  3. instantiated from here: errors...
    By advocation in forum C++ Programming
    Replies: 5
    Last Post: 03-27-2005, 09:01 AM
  4. Constructive Feed Back (Java Program)
    By xddxogm3 in forum Tech Board
    Replies: 12
    Last Post: 10-10-2004, 03:41 AM
  5. Struct *** initialization
    By Saravanan in forum C Programming
    Replies: 20
    Last Post: 10-09-2003, 12:04 PM