1
\$\begingroup\$

I'm a beginner in C# and trying to implement a player, an item interface, and some kind of storage system (for player inventory, NPC inventory/drop list, and storage like chests), and having some trouble implementing it in a way that requires the least work for a large amount of class types (and instances).

This is my current Player class:

namespace RogueBase.Classes
{
    public class Player
    {
        public Iitem[] inventory { get; set; }

        private int _hp;
        public int hp
        {
            get { return _hp; }
            set
            {
                if (value <= 0) _hp = 0;
                else if (value > 100) _hp = 100;
                else _hp = value;
            }
        }

        public Player()
        {
            hp = 100;
        }
    }
}

And my Storage class:

using RogueBase.Interfaces;
namespace RogueBase.Classes
{
    public class Storage
    {
        public Storage(int capacity)
        {
            inventory = new Iitem[capacity];
        }

        public bool Add(Iitem newItem)
        {
            for (int i = 0; i < inventory.Length; i++) // check each slot
            {
                if (inventory[i] as Iitem != null) { continue; } // skip items

                inventory[i] = newItem; // assign item to empty slot
                return true; // report success
            }
            return false; // inventory full
        }

        public bool Remove(Iitem targetItem)
        {
            for (int i = 0; i < inventory.Length; i++) // check each slot
            {
                if(inventory[i] == targetItem) // when match is found
                {
                    inventory[i] = null; // remove it
                    return true; // report success
                }
            }
            return false; // no item found
        }
    }
}

Item interface (just for reference):

namespace RogueBase.Interfaces
{
    public interface Iitem
    {
        string name { get; set; }
        int sellValue { get; set; }
        bool consumable { get; set; }

        void Equip();
        void Sell();
        void Consume();
    }
}

The problem right now is that every time I want to create a new inventory for something, I need to prepare a variable for it (not a problem when it comes to the player), but I'd like to be able to create friendly and hostile NPCs on demand with their own unique inventory that could be randomly generated,

In order to do this, is it my only option to turn the Storage class into an interface and copypaste the functions for every NPC/storage type? Or can I somehow turn the Add/Remove functions static? If I try to do it right now I get an error:

An object reference is required for the non-static field, method, or property 'Storage.inventory'

Edit; Specified question:

How can I access Iitem[] inventory in class Player to be used in class Storage's methods?

\$\endgroup\$
  • 1
    \$\begingroup\$ What is wrong with having an 'inventory' variable in each NPC? You could have a generateLoot() function in the storage or npc to generate loot. You can create a Corpse object and simply move the inventory there when a monstr dies- it is another chest object. \$\endgroup\$ – Felsir Jul 2 '16 at 17:22
  • \$\begingroup\$ @Felsir A slight oversight on my part, there's been a lot of new information to take in. That sounds like the way I'd like to implement the inventories, but I'm having trouble referencing the inventory variable (of the player) in the Storage class. Could you post your suggestion as an answer with some example code? \$\endgroup\$ – F8bit Jul 2 '16 at 19:00
  • 1
    \$\begingroup\$ You dont. You encapsulate the inventory array (and logic) within Storage class, like you had before. And let the player have variable of Storage type, for the code example see my updated answer. \$\endgroup\$ – wondra Jul 2 '16 at 23:33
  • \$\begingroup\$ Indeed, as your game grows the component pattern suits your needs best. \$\endgroup\$ – Felsir Jul 3 '16 at 6:55
4
\$\begingroup\$

Yes, you can turn the functions static, it has one downside: you need to keep track which inventory belongs to which object. A dictionary would do (simplified):

public static class InventoryManager {
  //map entity -> Storage, where entity is any type common for all entities that can have invetory
  // may it be common base, interface (even not related like ISpawnable) or just Object
  private static Dictionary<Entity,Storage> _storages = new Dictionary<Entity,Storage>();
  public static void AddItem(Entity entity, Iitem item) { 
     var storage = _storages.TryGetValue(entity);//try get
     //if not found, add it (remember also to delete it when not needed anymore!)
     if (storage == null) { _storages[entity] = (storage = new Storage()); }
     storage.Add(item);
  }
}

you can also add this keyword in function signature i.e. this Entity entity, making it an extension method, turning syntax InventoryManager.Add(orc1, axe) into orc1.Add(axe) like it was a member of the orcs NPC class.
One may also argue - why go static if they were derived from same type? You could add (non)virtual method handling inventory to the ancestor(base class).


In reaction to edit you were on the right track with the other option: You encapsulate the inventory array (and logic) within Storage class, like you had before. And let the player have variable of Storage type (or better rename Storage to Inventory and everything should be clearer), e.g.

//extra tip: implement IEnumerable<Iitem> it will allow linq to work on your invtory
public class Storage
{
  private Iitem[] inventory;
  //logic
}

//Id recommend also adding following interface
interface IHasInvetory {
   Storage Invetory { get; }
}

public class Player : IHasInvetory 
{
   public Storage Invetory { get; set; }
   //rest of the class
}
\$\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.