[C#] Inventory System

Started by
8 comments, last by violentcrayon 16 years, 9 months ago
So I'm working on a console (text-based, that is) RPG in C#. I've implemented scripting via LUA for the purposes of creating rooms, npcs, and talking to the npcs. Room exploration hasn't been done yet as I feel that I should have the complete game in one room, so to speak. Anyway. I'm starting to think about the inventory system. Yeah I did a search on it for Google and on GameDev, but didn't really find much of anything (which surprises me somewhat). So here is what I was thinking. I would write some stuff in an XML file for each item. Each item would have a unique ID number. For example, a potion of life might have an id number of 1 and would have an attribute (is that what it's called? I don't have any XML experience but will be looking into it) called lifeRestored, and I will set that to, say, 5. Then, in the game itself, I will have something like

switch (uniqueID)
{
case 1:
DrinkLifePotion();
break;
case2:
EquipWeapon();
break;
//etc
}

to decide what to do based on the unique ID of the item. Then, I would obviously have a method like

public void DrinkLifePotion()
{
//parse lifeRestored from XML file
lifeHealed; //would equal the value from the XML file

player.HP += lifeHealed;
}

And so on for each item. Each time a player picks an item up, the item's unique ID is stored into an array. That would be how the program would know which items are stored in the array. Then, to display the inventory, it would check the number in the array against the numbers in the XML file, and each time it finds a match, display the name that owns that unique ID number. Is this a viable solution? Is there a better way to go about doing this? Any help is GREATLY appreciated. Thanks!
http://neolithic.exofire.net
Advertisement
Yes, there are better ways.

Make an item base class. Make a public virtual UseItem(), EquipItem(), methods in the base class.

Now make classes that inherit the item base class. So you would have a potion class and a sword class.

When you try to Use the item you call the UseItem method that is in each class through the base class. That means you really don't need to know what the item is and it will do what it is suppose to do.

This also means you can add new items without having to go back and change your old code, just add a new inherited class.

theTroll
You use XML to persist your in-game objects. It's not intended for life transformation (although it can be done, EE-grade software does it all the time, X-Path and similar).

Unfortunately, you then immediately run into a whole lot of issues regarding identities, dependencies and other deal-breaking things.

There's an article in Game Programming Gems 6 on Component oriented architecture, which natively supports run-time configuration and XML persistence.

You really don't want to deal with IDs as such in your code. Too prone to abuse or mistake. Your inventory contains objects. One useful approach here is inversion of control, the other is command pattern.

The idea is something like this:
class Item{  virtual void apply( Object target );}class HealingItem : public Item{  int healingStrength;  virtual void apply( Object target )  {    if ( target is CreatureObject ) {       // cannot use on monsters     }    if ( target is PlayerObject ) {      if (target.isFriendly() ) {        // heal target      }    }  }}


This allows you to handle the GUI part through commands:
class Command{  virtual void execute();};class UseItemCommand : public Command{  UseItemCommand( Object item, Object target );  virtual void execute()  {    item->apply(target);  }};....// on double click on item{  CommandQueue.push( new UseItemCommand( Inventory.getSelectedItem(), UI.getCurrentTarget() ) );}


This dives you nice decoupled design into which you can add arbitrary number of items.

XML persistence is separate topic, and simply involves writing the values for various items to/from XML. There should be plenty of topics on "XML persistence", "XML serialization", ... This is performed only on explicit request, usually during loading of level.
Question answered before post was posted.
http://neolithic.exofire.net
Well I think as you're using lua and trying to implement a inventory system using external file, so you will probably better consider the solution you came up with.

Check out the piece of code you provided bellow

switch (uniqueID)
{
case 1:
DrinkLifePotion();
break;
case2:
EquipWeapon();
break;
//etc
}
[\code]

What if you need to add a new item to the inventory? You will have to hard code a new case everytime you create a new item, also you will have to update the xml items list and load the file?
I think a better aproach would be read the xml file and store you items "properties" to class or struct. Then you would have some kind of collection for storing these objects "items".

Hope this helps
blog: www.brasilokau.com/games/blog
Quote:Original post by Antheus
You use XML to persist your in-game objects. It's not intended for life transformation (although it can be done, EE-grade software does it all the time, X-Path and similar).

Unfortunately, you then immediately run into a whole lot of issues regarding identities, dependencies and other deal-breaking things.

There's an article in Game Programming Gems 6 on Component oriented architecture, which natively supports run-time configuration and XML persistence.

You really don't want to deal with IDs as such in your code. Too prone to abuse or mistake. Your inventory contains objects. One useful approach here is inversion of control, the other is command pattern.

The idea is something like this:
*** Source Snippet Removed ***


Thanks so much! That clears things up quite a bit. So, using your code, then if the user says he wants to use the healing potion, I would use

Item.Apply( HealingItem )

right?

http://neolithic.exofire.net
Most likely you would have some type of array or container holding your inventory objects. This array would be of the Item type, and would be able to hold any object that inherits Item.

So create an Item[] inventory;

To call the UseItem.. iventory[2].UseItem();

theTroll
Now if you want to add a bit more flexibility and a bit of complexity you can use reflection.

Instead of hard coding all the things you can do with an object in your UI, you have the object tell the UI what all an object can do. This means that in the future you can add something you never even considered without breaking everything.

This does add a lot of complexity in the design and code.

theTroll
Quote:Original post by violentcrayon

Thanks so much! That clears things up quite a bit. So, using your code, then if the user says he wants to use the healing potion, I would use

Item.Apply( HealingItem )

right?


Not quite. In OOP, we call the function upon the *object*, not its class. Here, Item and HealingItem are class names. Classes define types, so we can make things which are HealingItems, in the same way that we can make things which are ints.

The inventory will contain Items. All Items can be .apply()d to a target; the effect is determined by what kind of Item it is. HealingItems heal the thing they're applied to. We don't need to check the Item-kind ourselves; though; that's what all the 'virtual' setup does for us - Items "know" what kind of Item they are, and do their corresponding action when we apply them.

So, in short, the User would select an item out of the inventory - perhaps by number; then we would get a reference to that Item by indexing into the inventory. Then to use it, we call the .apply *of that item*, and specify the Player as a target. (This also allows us to have Creatures with inventories and the ability to use items, if we're sufficiently careful.)
Thanks for the help, everyone. Now I have the following code, and it works!

class Program    {        public static int HP;                static void Main(string[] args)        {            Program program = new Program();            program.InvetoryTest();        }        public void InvetoryTest()        {            HP = 5;            HealingItem heal = new HealingItem();            HarmfulItem harm = new HarmfulItem();            Item[] inventory;            inventory = new Item[] { heal, harm };            Console.WriteLine(HP);            inventory[0].ApplyItem();            Console.WriteLine(HP);            inventory[1].ApplyItem();            Console.WriteLine(HP);            Console.ReadLine();        }    }    public class Item    {        public virtual void ApplyItem()        {            //nothing happens here...it's always overridden        }    }    public class HealingItem : Item    {        public override void ApplyItem()        {            Program.HP += 5;        }    }    public class HarmfulItem : Item    {        public override void ApplyItem()        {            Program.HP -= 3;        }    }}


A little more tweaking, testing, adding, etc..., and things should be great. Thanks again!
http://neolithic.exofire.net

This topic is closed to new replies.

Advertisement