Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Inventory - creating new item with same ID

Discussion in 'Scripting' started by mrgohut, May 2, 2014.

  1. mrgohut

    mrgohut

    Joined:
    Feb 8, 2014
    Posts:
    134
    Code (csharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. using System.Collections.Generic;
    4.  
    5. public class Inventory : MonoBehaviour {
    6.  
    7.     public SimpleMouseRotator camera1;
    8.     public SimpleMouseRotator camera2;
    9.  
    10.     public int slotsX, slotsY;
    11.  
    12.     public GUISkin skin;
    13.  
    14.     public List<Item> inventory = new List<Item>();
    15.     public List<Item> slots = new List<Item>();
    16.  
    17.     public bool showInventory;
    18.     private bool showTooltip;
    19.     private bool draggingItem;
    20.     private Item draggedItem;
    21.  
    22.     private string tooltip;
    23.  
    24.     private ItemDatabase database;
    25.  
    26.     private int prevIndex;
    27.  
    28.     void Start()
    29.     {
    30.         camera1 = GameObject.FindWithTag("Player").GetComponent<SimpleMouseRotator>();
    31.         camera2 = GameObject.FindWithTag("MainCamera").GetComponent<SimpleMouseRotator>();
    32.         database = GameObject.FindGameObjectWithTag("ItemDatabase").GetComponent<ItemDatabase>();
    33.  
    34.         for(int i = 0; i < (slotsX * slotsY); i++)
    35.         {
    36.             slots.Add(new Item());
    37.             inventory.Add(new Item());
    38.         }
    39.         AddItem(0);
    40.         AddItem(1);
    41.         AddItem(2);
    42.     }
    43.  
    44.     void Update()
    45.     {
    46.         if(Input.GetKey(KeyCode.Y))
    47.         {
    48.             AddItem(2);
    49.         }
    50.         if(Input.GetKeyDown(KeyCode.Tab))
    51.         {
    52.             showInventory = !showInventory;
    53.         }
    54.         if(showInventory)
    55.         {
    56.             camera1.enabled = false;
    57.             camera2.enabled = false;
    58.         }
    59.         else
    60.         {
    61.             camera1.enabled = true;
    62.             camera2.enabled = true;
    63.         }
    64.     }
    65.  
    66.     void OnGUI()
    67.     {
    68.         tooltip = "";
    69.         GUI.skin = skin;
    70.         if(showInventory)
    71.         {
    72.             DrawInventory();
    73.             if(showTooltip)
    74.                 GUI.Box(new Rect(Event.current.mousePosition.x + 15f, Event.current.mousePosition.y, 200, 200), tooltip, skin.GetStyle("Tooltip"));
    75.         }
    76.         if(draggingItem)
    77.         {
    78.             GUI.DrawTexture(new Rect(Event.current.mousePosition.x, Event.current.mousePosition.y, 50, 50), draggedItem.itemIcon);
    79.         }
    80.     }
    81.  
    82.     void DrawInventory()
    83.     {
    84.         Event e = Event.current;
    85.         int i = 0;
    86.         for(int y = 0; y < slotsY; y++)
    87.         {
    88.             for(int x = 0; x < slotsX; x++)
    89.             {
    90.                 Rect slotRect = new Rect(x * 60, y * 60, 50, 50);
    91.                 GUI.Box(slotRect, "", skin.GetStyle("Slots"));
    92.                 slots[i] = inventory[i];
    93.                 int itemCount = inventory[i].itemCount;
    94.                 if(slots[i].itemName != null)
    95.                 {
    96.                     GUI.DrawTexture(slotRect, slots[i].itemIcon);
    97.                     GUI.Label(new Rect(x * 60,y * 60,50,50), itemCount.ToString());
    98.                     if(slotRect.Contains(e.mousePosition))
    99.                     {
    100.                         tooltip = CreateTooltip(slots[i]);
    101.                         showTooltip = true;
    102.                         //przenoszenie przedmiotów - podnieś
    103.                         if(e.button == 0  e.type == EventType.mouseDrag  !draggingItem)
    104.                         {
    105.                             draggingItem = true;
    106.                             prevIndex = i;
    107.                             draggedItem = slots[i];
    108.                             inventory[i] = new Item();
    109.                         }
    110.                         //przenoszenie przedmiotów - upuść
    111.                         if(e.type == EventType.mouseUp  draggingItem)
    112.                         {
    113.                             inventory[prevIndex] = inventory[i];
    114.                             inventory[i] = draggedItem;
    115.                             draggingItem = false;
    116.                             draggedItem = null;
    117.                         }
    118.                         //Używanie przedmiotów
    119.                         if(e.isMouse  e.type == EventType.mouseDown  e.button == 1)
    120.                         {
    121.                             print("Clicked " + i);
    122.                             if(inventory[i].itemType == Item.ItemType.Consumable)
    123.                             {
    124.                                 if(inventory[i].itemCount == 1)
    125.                                 {
    126.                                     UseConsumable(slots[i], i, true, false);
    127.                                 }
    128.                                 else
    129.                                 {
    130.                                     UseConsumable(slots[i], i, false, true);
    131.                                 }
    132.                             }
    133.                         }
    134.                     }
    135.                 }
    136.                 else
    137.                 {
    138.                     if(slotRect.Contains(e.mousePosition))
    139.                     {
    140.                         if(e.type == EventType.mouseUp  draggingItem)
    141.                         {
    142.                             inventory[i] = draggedItem;
    143.                             draggingItem = false;
    144.                             draggedItem = null;
    145.                         }
    146.                     }
    147.                 }
    148.                 if(tooltip == "")
    149.                 {
    150.                     showTooltip = false;
    151.                 }
    152.                 i++;
    153.             }
    154.         }
    155.     }
    156.  
    157.     //wyświetlanie opisu przedmiotu po najechaniu na niego myszką
    158.     string CreateTooltip(Item item)
    159.     {
    160.         tooltip = "<color=#ffffff>" + item.itemName + "</color>\n\n" + item.itemDesc;
    161.         return tooltip;
    162.     }
    163.  
    164.     void RemoveItem(int id)
    165.     {
    166.         for(int i = 0; i < inventory.Count; i++)
    167.         {
    168.             if(inventory[i].itemID == id)
    169.             {
    170.                 inventory[i] = new Item();
    171.                 break;
    172.             }
    173.         }
    174.     }
    175.  
    176.     void AddItem(int id)
    177.     {
    178.         for(int i = 0; i < inventory.Count; i++)
    179.         {
    180.             //Jeżeli nie istnieje, dodaj item
    181.             if(inventory[i].itemName == null)
    182.             {
    183.                 for(int j = 0; j < database.items.Count; j++)
    184.                 {
    185.                     if(database.items[j].itemID == id)
    186.                     {
    187.                         inventory[i] = database.items[j];
    188.                     }
    189.                 }
    190.                 break;
    191.             }
    192.             //Jeżeli istnieje dodaj +1 do licznika
    193.             else
    194.             {
    195.                 if(inventory[i].itemID == id)
    196.                 {
    197.                     //sprawdź czy licznik wyniósł 200
    198.                     //jeżeli tak, to stwórz nowy item
    199.                     if(inventory[i].itemCount == 200)
    200.                     {
    201.                         if(inventory[i].itemName == null)
    202.                         {
    203.                             for(int j = 0; j < database.items.Count; j++)
    204.                             {
    205.                                 if(database.items[j].itemID == id)
    206.                                 {
    207.                                     inventory[i] = database.items[j];
    208.                                     //i ustaw licznik na 0 dla nowego itema
    209.                                     inventory[i].itemCount = 1;
    210.                                     break;
    211.                                 }
    212.                             }
    213.                         }
    214.                     }
    215.                     //jeżeli nie, dodaj +1
    216.                     else
    217.                     {
    218.                         inventory[i].itemCount += 1;
    219.                         break;
    220.                     }
    221.                 }
    222.             }
    223.         }
    224.     }
    225.     /*
    226.     void AddItemCount(int id)
    227.     {
    228.         for(int i = 0; i < inventory.Count; i++)
    229.         {
    230.             if(inventory[i].itemName != null)
    231.             {
    232.                 inventory[i].itemCount += 1;
    233.                 break;
    234.             }
    235.         }
    236.     }
    237.     */
    238.     bool InventoryContains(int id){
    239.         foreach(Item item in inventory){
    240.             if(item.itemID == id) return true;
    241.         }
    242.         return false;
    243.     }
    244.  
    245.     //Używanie itemów
    246.     private void UseConsumable(Item item, int slot, bool deleteItem, bool deleteCount)
    247.     {
    248.         //switch (zostawić)
    249.         switch(item.itemID)
    250.         {
    251.             //case id, np. jabłko ma id 4 -> case 4: .... coś zrób
    252.         case 2:
    253.         {
    254.             print("Mnom, mnom, mnom");
    255.             break;
    256.         }
    257.         }
    258.         //jeżeli wysłana informacja o usunięciu
    259.         if(deleteItem)
    260.             inventory[slot] = new Item();
    261.         //jeżeli wysłana informacja o zmianie licznika
    262.         if(deleteCount)
    263.         {
    264.             for(int i = 0; i < inventory.Count; i++)
    265.             {
    266.                 if(inventory[i].itemID == item.itemID)
    267.                 {
    268.                     inventory[i].itemCount -= 1;
    269.                     break;
    270.                 }
    271.             }
    272.         }
    273.     }
    274. }
    275.  
    i got this and now "Berry" is stackable max to 200. When it reach 200 i need to create new "Berry" with count 1 and then if i again hold "Y" it add stacks to this new Berry. I don't know how can i do this.

    I tried, but when i reach 200 it create new "Berry" but with 200 stacks ;/


    Someone can help me ? ;/
     
    Last edited: May 2, 2014
  2. LeftyRighty

    LeftyRighty

    Joined:
    Nov 2, 2012
    Posts:
    5,148
    check this code chunk actually happens:

    because how can an inventory slot have a 200 qty and not have an itemName??

    could you just break out of the loop when the qty is 200... essentially skipping that slot because it's "full" and keep looking for the next available empty slot to put stuff in. It would save repeating the "put stuff in new slot" code.

    http://answers.unity3d.com/questions/555467/stopping-a-loop-return-or-break.html
     
    Last edited: May 2, 2014
  3. mrgohut

    mrgohut

    Joined:
    Feb 8, 2014
    Posts:
    134
    hmm okay ;D I made progress, now when it reach 200 it create new Berry with 1 but .... every Berry take this value xD and i dont know how to hold it on only one slot and does not affect the rest
    Code (csharp):
    1.     void AddItem(int id)
    2.     {
    3.         for(int i = 0; i < inventory.Count; i++)
    4.         {
    5.             //Jeżeli nie istnieje, dodaj item
    6.             if(inventory[i].itemName == null)
    7.             {
    8.                 for(int j = 0; j < database.items.Count; j++)
    9.                 {
    10.                     if(database.items[j].itemID == id)
    11.                     {
    12.                         inventory[i] = database.items[j];
    13.                         inventory[i].itemCount = 1;
    14.                     }
    15.                 }
    16.                 break;
    17.             }
    18.             //Jeżeli istnieje dodaj +1 do licznika
    19.             else
    20.             {
    21.                 if(inventory[i].itemID == id)
    22.                 {
    23.                     if(inventory[i].itemCount != 200)
    24.                     {
    25.                         inventory[i].itemCount += 1;
    26.                         break;
    27.                     }
    28.                 }
    29.             }
    30.         }
    31.     }
     
    Last edited: May 2, 2014
  4. toreau

    toreau

    Joined:
    Feb 8, 2014
    Posts:
    204
    I don't have any suggestion on how to solve your problem, because I disagree with your whole approach to your inventory system. Please don't take this the bad way, but I've created an inventory system that works just out of the box, and I've blogged about it:

    http://gamedev.aursand.no/2014/04/27/cloning-rust-part-4/

    The problem with your approach is that it's not agnostic enough, and you will encounter much bigger problems than you are experiencing right now. And, yes, I've encountered most of the problems possible to encounter. ;)

    Feel free to ask, comment and what not. :)
     
  5. mrgohut

    mrgohut

    Joined:
    Feb 8, 2014
    Posts:
    134
    Thanks for help but i want to solve this problem with my code ;]
     
  6. Suddoha

    Suddoha

    Joined:
    Nov 9, 2013
    Posts:
    2,824
    Ok, let me try to explain this phenomenon:

    The sitaution is the following:

    You've got a list with all items which are available (your database).
    And you have a list of items which are in your inventory.

    Let's say you got an 'item' in your database : db-item1
    Your inventory items will be called inv-item1, inv-item2

    The thing is, these are no objects and therefore not your real items, just references.
    Thus, we call the objects (the real items) obj1 etc.


    If you add any content from your database to your inventory, let's say inv-item1 equals db-item1, you actually copy the reference to obj1 or in other words, you tell your inventory element inv-item1 to reference obj1 just like db-item1 in your database does.

    Altering db-item1 or inv-item1 will both affect your original object obj1, as they're just references to obj1. Now, if you say inv-item2 is equal to db-item1 (because your stack in slot 1 is full) it will also reference obj1.
    Doing anything with inv-item2 will now also affect obj1, and if you access values via inv-item1 or db-item1, you will notice they same changes have been applied to them... actually not to 'them', because their just referencing the one, single object that, in the beginning, was only referenced by your database element db-item1.

    You might wanna test this yourself: If you add several items of the same type to your inventory, Debug.Log your database and see what has happened.
     
    Last edited: May 2, 2014
  7. mrgohut

    mrgohut

    Joined:
    Feb 8, 2014
    Posts:
    134
    Hmm okay but i cant change my item ID when i create new one in the next slot. I think i need to "freeze" or something item with 200 stacks.

    For me its hard to do, but propably its very easy >.<
     
  8. Suddoha

    Suddoha

    Joined:
    Nov 9, 2013
    Posts:
    2,824
    Well, what you could do is creating a new object for a new stack of items, but this should already be done when adding one item for the first time as you will otherwise always alter your database items whenever you change something in your inventory.

    By creating a new object i mean you should do a 'real' copy ob the item (new keyword as a hint) which then is an independant object and can be modified without altering the database version.


    But i would suggest to create one object per/slot (stack) and not one object for each item in a stack as toreau has done it in the example. That would be a bit too much unless you really need to trace and treat every single item in a stack.
     
  9. toreau

    toreau

    Joined:
    Feb 8, 2014
    Posts:
    204
    Thanks for your input in this thread. I would like to point out that the whole point of my inventory system is to treat each item individually. In many cases it might be overkill, but I found it to be beneficient, especially in terms of individual items being altered over time, for example in regards to decay, the items being cooked and so on. In my opinion, my approach makes it so much easier.

    Also, my approach is low-weight - no prefabs or anything, just non-Monobehaviour objects attached to slots, which in turn are attached to the InventoryController, and it is perfectly logical. You don't add/subtract the number of items in each slot, instead you treat each item as a "real world object".

    In addition, it's super-easy to serialize/deserialize, being to/from a storage or over the network.
     
    Last edited: May 2, 2014
  10. Suddoha

    Suddoha

    Joined:
    Nov 9, 2013
    Posts:
    2,824
    I didn't want to make your system look bad, i just mentioned that he's rather looking for the suggestion i made as stackable items are often items which are always the same, at least in most games i've played so far and it's obviously the way he wanted to do it.

    With objects in my example i meant instances of the item class too, not gameobjects.
     
  11. toreau

    toreau

    Joined:
    Feb 8, 2014
    Posts:
    204
    We're having different opinions here, and I think that is just a good thing. My thing is also a stackable system, with only the same item in each slot etc., but I still think the thinking here is a bit "backwards";

    With my inventory system, I treat it in a natural way; items are individual - uhm - items, so they can share a lot attributes, but also be different. If you want things like decay, or any other manipulation of the items, this is a much better approach (and, seriously, I've tried them all). :)

    My first attempt at my inventory system was also to treat each slot as an item, and just have a "howManyOfThem" variable to it. It works, by all means, but it limits your ability to do crazy stuff with each item in the future. And its just as easy to treat each item as a "real" item. :)

    We agree on some things, but disagree on other things, but I hope that's OK. In the end, I hope mrgohut learn something from it. :)

    UPDATE: Maybe the most important reason I went with my approach, is that the inventory is totally agnostic, which means that I can attach it to any GameObject, be it a Player, a Tree, a Rock or whatever.
     
    Last edited: May 2, 2014
  12. Suddoha

    Suddoha

    Joined:
    Nov 9, 2013
    Posts:
    2,824
    Of course that's okay, it's always good to try many different things and find out which way fits our needs. :p
     
  13. mrgohut

    mrgohut

    Joined:
    Feb 8, 2014
    Posts:
    134
    Thanks guys for reply, but I'm propably a rock now xD I don't get it at all. I know what my code do now but i still can't understand how can i fix it :<
    Sorry guys.
     
  14. Suddoha

    Suddoha

    Joined:
    Nov 9, 2013
    Posts:
    2,824
    Depends on which version you'd like as a basis for your inventory.

    For now, try this:

    Create a contructor in your item class, which takes another item as a parameter.
    Code (csharp):
    1.  
    2. // in your Item class
    3.  
    4. public Item(Item i) // constructor doesn't have a return type
    5. {
    6.      this.xxx = i.xxx;
    7.      this.yyy = i.yyy;
    8.      // and so on, while xxx, yyy etc should be datatypes and no other reference types
    9. }
    10.  
    If you now execute the following code
    Code (csharp):
    1.  
    2. Item aRealCopy = new Item(theOriginal);
    3.  
    you will have an exact copy of the original item which you can modify without altering the original in your database.

    In your code, unless you want to rewrite and try again, everytime you want to start a new stack (at least then!) you should write

    Code (csharp):
    1.  
    2. // in your second post this is line 6-13
    3. if(database.items[j].itemID == id)
    4.  
    5.                     {
    6.                         //inventory[i] = database.items[j]; // this is the old line
    7.                         inventory[i] = new Item(database.items[j]); // this will not set the reference to the item your database is referencing
    8.                         // but will create a new object (an exact independant copy) and reference this one instead
    9.                         inventory[i].itemCount = 1;
    10.                     }
    11.  
     
    Last edited: May 2, 2014
  15. mrgohut

    mrgohut

    Joined:
    Feb 8, 2014
    Posts:
    134
    Okay, so this is my Item.cs

    Code (csharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. [System.Serializable]
    5. public class Item {
    6.  
    7.     public string itemName;
    8.     public int itemID;
    9.     public string itemDesc;
    10.     public Texture2D itemIcon;
    11.     public int maxAmount;
    12.     public int AmountNow;
    13.     public ItemType itemType;
    14.  
    15.     public enum ItemType
    16.     {
    17.         Weapon,
    18.         Consumable,
    19.         Resource
    20.     }
    21.  
    22.     public Item(string name, int id, string desc, int maxAm, int Amount, ItemType type)
    23.     {
    24.         itemName = name;
    25.         itemID = id;
    26.         itemDesc = desc;
    27.         itemIcon = Resources.Load<Texture2D>("ItemIcons/" + name);
    28.         maxAmount = maxAm;
    29.         AmountNow = Amount;
    30.         itemType = type;
    31.     }
    32.  
    33.     public Item()
    34.     {
    35.  
    36.     }
    37. }
    Here AddItem from Inventory.cs
    Code (csharp):
    1.     void AddItem(int id)
    2.     {
    3.         for(int i = 0; i < inventory.Count; i++)
    4.         {
    5.             //Jeżeli nie istnieje, dodaj item
    6.             if(inventory[i].itemName == null)
    7.             {
    8.                 for(int j = 0; j < database.items.Count; j++)
    9.                 {
    10.                     if(database.items[j].itemID == id)
    11.                     {
    12.                         inventory[i] = new Item(database.items[j]);
    13.                         inventory[i].AmountNow = 1;
    14.                     }
    15.                 }
    16.                 break;
    17.             }
    18.         }
    19.     }
    and here my ItemDatabase.cs
    Code (csharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. using System.Collections.Generic;
    4.  
    5. public class ItemDatabase : MonoBehaviour {
    6.  
    7.     public List<Item> items = new List<Item>();
    8.  
    9.     void Start()
    10.     {
    11.         items.Add(new Item("Stone", 0, "Stone.", 200, 1, Item.ItemType.Resource));
    12.         items.Add(new Item("Wood", 1, "Wood.", 200, 1, Item.ItemType.Resource));
    13.         items.Add(new Item("Berry", 2, "Berry.", 200, 1, Item.ItemType.Consumable));
    14.     }
    15.  
    16. }
    17.  
    That's how i did. I know that it can't work now.
    This:
    Code (csharp):
    1. inventory[i] = new Item(database.items[j]);
    but i cant do this with new Item();
    Code (csharp):
    1. Item aRealCopy = new Item(theOriginal);
    So i must use a GameObjects, ye ?
     
  16. Suddoha

    Suddoha

    Joined:
    Nov 9, 2013
    Posts:
    2,824
    Why can't you use new Item? And no, you won't need any gameobject for that.
     
  17. mrgohut

    mrgohut

    Joined:
    Feb 8, 2014
    Posts:
    134
    Because to use new Item(); i need
    Code (csharp):
    1.     public string itemName;
    2.     public int itemID;
    3.     public string itemDesc;
    4.     public Texture2D itemIcon;
    5.     public int maxAmount;
    6.     public int AmountNow;
    7.     public ItemType itemType;
    use this, so it looks like:
    Code (csharp):
    1.  
    2. new Item("Stone", 0, "Stone.", 200, 1, Item.ItemType.Resource)
    3.  
     
  18. Suddoha

    Suddoha

    Joined:
    Nov 9, 2013
    Posts:
    2,824
    I know what you meant, but i think you didn't quite understand what i was trying to explain. :)

    For your database, you created (i.e.) the item which you posted above:

    Code (csharp):
    1.  
    2. database[0] = new Item("Stone", 0, "Stone.", 200, 1, Item.ItemType.Resource)
    3.  
    Now, database[0] will reference an object with these attributes.
    As you want your database not to be affected by any changes when you need the item, you have to created a new object (not talking about gameObjects here, but about instances of a class) which you can adjust for your needs, i.e. increment the current amount of the item in your inventory.

    This is where the contructor will be helpful:
    Code (csharp):
    1.  
    2. public Item(Item i)
    3. {
    4.      this.itemName = i.itemName;
    5.      this.itemID = i.itemID;
    6.      this.itemDesc = i.itemDesc;
    7.      this.itemIcon = i.itemIcon;
    8.      this.maxAmount = i.maxAmount;
    9.      this.AmountNow = i.AmountNow;
    10.      this.itemType = i.itemType;
    11. }
    12.  
    This code will create a new identical object which you can modify and add to your inventory which, in your case, should always be done when you start to fill a new slot so that you have the same items as different instances of your item class in your inventory. If you now modify the amount of items in the second slot, it will not affect the item stack in the first slot.
     
    Last edited: May 3, 2014
  19. mrgohut

    mrgohut

    Joined:
    Feb 8, 2014
    Posts:
    134
    Hmm okay. But now i must create new database ?
    Code (csharp):
    1.  
    2.     void AddItem(int id, int Amount)
    3.     {
    4.         for(int i = 0; i < inventory.Count; i++)
    5.         {
    6.             if(inventory[i].itemName == null)
    7.             {
    8.                 for(int d = 0; d < database.items.Count; d++)
    9.                 {
    10.                     if(database.items[d].itemID == id)
    11.                     {
    12.                         inventory[i] = database.items[d];
    13.                     }
    14.                 }
    15.                 break;
    16.             }
    17.         }
    18.     }
    19.  
    here i must do something like this ?
    Code (csharp):
    1.  
    2.     void AddItem(int id, int Amount)
    3.     {
    4.         for(int i = 0; i < inventory.Count; i++)
    5.             //Looping all slots
    6.         {
    7.             if(inventory[i].itemName == null)
    8.                 //if empty slot
    9.             {
    10.                 for(int d = 0; d < database.items.Count; d++)
    11.                     //search for item in database
    12.                 {
    13.                     if(database.items[d].itemID == id)
    14.                         //if ID from AddItem() = ID in database
    15.                     {
    16.                         //ADD ITEM
    17.  
    18.                         //?!?!?!?!
    19.                         //inventory[i] = database.items[d]; <----- old lane
    20.                         //Here add this item from second database ?
    21.                         //I need to add item with this: public Item(Item i) ?
    22.                         //?!?!?!?!
    23.                     }
    24.                 }
    25.                 break;
    26.                 //STOP.
    27.             }
    28.         }
    29.     }
    30.  
    Meh, don't be angry :(