4
\$\begingroup\$

I am trying to create a inventory screen / system for my game. And I don't know how it will work. I'm creating it in unity. I was thinking of making a database of all items and a database of items in inventory. However unity has no database function. Another problem would be using a web database. Every single player can't have their own database, it would be overkill.

I haven't started writing any code for the inventory but only planning for it. The type of inventory system I am planning is similar to skyrim. List on left and stats for items on the right.

\$\endgroup\$

2 Answers 2

8
\$\begingroup\$

I recommend that you do not "pass around Items" as an actual object, but instead, have each item stored in a Dictionary<int,GameItem>. Each item has it's own integer id, which you pass around and store in the inventory. So say Iron Ore has an id of 4, and you have 18 of them. In your inventory there would be a struct that says 18, 4. You then use the id to fetch the actual item from a Dictionary. Doing it this way will greatly reduce, if not completely eliminate, stressing out the garbage collector. You can also think of it like how instancing models in OpenGL or DirectX works, why would you initialize a tree model hundreds of times when you could just initialize it once and reuse it?

I also wanted to mention that this is how most, if not all, modern games handle their in game resources. A good example being Skyrim, which uses an id for literally everything. When a player opens up their inventory, they are simply querying the Dictionary with the integer ids in their inventory; which is then read and converted to a presentation layer, showing the item's name and attributes.

And as a final note, the only limitation to this is ((2^31)-1) items, which again can also be doubled if you use an unsigned integer. But let's be honest right now, not even MMO's like World of Warcraft have anywhere close integer max number of items. (Wowhead says 100,458 total items)

Here is a brief example of what your inventory should actually be holding.

using System;

namespace Your.Game.Framework.Namespace
{
    public struct ItemStack : IEquatable<ItemStack>
    {

        public int ID { get; }
        public int Quantity { get; }
        public const int MinimumItemQuantity = 0;

        public ItemStack(int id, int quantity)
        {
            this.ID = id;
            this.Quantity = quantity;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public ItemStack ToEmptyQuantity()
        {
            return new ItemStack(this.ID, 0);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public override bool Equals(object obj)
        {
            if (ReferenceEquals(null, obj)) return false;
            return obj is ItemStack && Equals((ItemStack)obj);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public override int GetHashCode()
        {
            unchecked
            {
                return (ID * 397) ^ Quantity;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        public static bool operator ==(ItemStack a, ItemStack b)
        {
            return a.Equals(b);
        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        public static bool operator !=(ItemStack a, ItemStack b)
        {
            return !(a == b);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="other"></param>
        /// <returns></returns>
        public bool Equals(ItemStack other)
        {
            return this.ID == other.ID && this.Quantity == other.Quantity;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="packet"></param>
        /// <param name="quantity"></param>
        /// <returns></returns>
        public static ItemStack operator +(ItemStack packet, int quantity)
        {
            return new ItemStack(packet.ID, packet.Quantity + quantity);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="packet"></param>
        /// <param name="multiplier"></param>
        /// <returns></returns>
        public static ItemStack operator *(ItemStack packet, int multiplier)
        {
            return new ItemStack(packet.ID, packet.Quantity * multiplier);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="packet"></param>
        /// <param name="divisor"></param>
        /// <returns></returns>
        public static ItemStack operator /(ItemStack packet, int divisor)
        {
            return new ItemStack(packet.ID, ClampMinimum(packet.Quantity / divisor, MinimumItemQuantity));
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="packet"></param>
        /// <param name="quantity"></param>
        /// <returns></returns>
        public static ItemStack operator -(ItemStack packet, int quantity)
        {
            return new ItemStack(packet.ID, ClampMinimum(packet.Quantity - quantity, MinimumItemQuantity));
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="value"></param>
        /// <param name="minimum"></param>
        /// <returns></returns>
        private static int ClampMinimum(int value, int minimum)
        {
            return value < minimum ? minimum : value;
        }
    }
}

As a sort of update, I also wanted to express that this implementation doesn't need to be a struct. If you want optimal performance in terms of avoiding garbage collection, a struct is the way to go. However, depending on the scale of your game, you could easily use a class, and further, a string ID instead of an integer ID. It all depends on the kind of game you're making; there is no clear cut answer. Look at your game, prototype both implementations, and see which one works better for you.

\$\endgroup\$
4
  • \$\begingroup\$ Do you still recommend a list for the players inventory for reference. \$\endgroup\$ Commented Nov 14, 2016 at 1:08
  • \$\begingroup\$ @Treechapter I would recommend a List<YourItemStruct>, yes. The goal in all of this is to reduce processing and IO reads. Cache and reuse as much as you can. \$\endgroup\$
    – Krythic
    Commented Nov 14, 2016 at 1:12
  • \$\begingroup\$ @Treeschapter See my new update. \$\endgroup\$
    – Krythic
    Commented Nov 14, 2016 at 1:34
  • \$\begingroup\$ As an extra side note, the division of ItemStacks should be handled to deal with a remainder for odd quantity-sized ItemStacks. \$\endgroup\$
    – Krythic
    Commented Mar 14, 2017 at 20:50
-3
\$\begingroup\$

You can use C# Arrays or Lists and Classes; Make an Item class/struct which has all the properties and stats of the item; Name, Quantity, Weight, etc. Then for each item in the game, make an object of the class/struct with the items properties. Store all game items in an Global list, each player should have their own list of their inventory items. When the player collects an item, you will add that item to the player's inventory list using List.Add function and when the player removes an item, you remove it using List.Remove. You can use the unity's newly introduced UI system to show the player's items and their corresponding stats.

\$\endgroup\$
1
  • 1
    \$\begingroup\$ You should use integer ids, not the actual item. \$\endgroup\$
    – Krythic
    Commented Nov 14, 2016 at 1:00

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .