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. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice

Inventory Slot Clear Tile Left Behind

Discussion in 'Scripting' started by Derpybunneh, Dec 31, 2016.

  1. Derpybunneh

    Derpybunneh

    Joined:
    Mar 26, 2015
    Posts:
    6
    Hello! So I have a relatively simple inventory system with a display that displays different tiles I pick up. The way it works is that I store an array of the slot UI game objects, and then when I pick up a tile I find an Image game object in the slot and set the sprite to the sprite of the tile I just picked up. The way I've programmed it is that when I remove the inventory item, it subtracts its quantity, and if it's quantity value is equal to 0, it clears the title (image, quantity, and all that). I've put this updateDisplay function that will automatically shift the display of the titles to the left as tiles are cleared.

    This function works wonderfully well, except for when I have more than 2 items. If item A is cleared, Item B moves over to Item A's original slot, and item C moves to Item B's slot, while still leaving behind itself in it's original slot. Something with the loop I use to find the slots and clear must be off.

    Any help with figuring out the issue would be very much appreciated!

    Remove Item from Inventory Code: (ignore the commented out code)
    Code (CSharp):
    1. public void removeTile(int itemID, int amount) {
    2.         // Check to see if tile exists in inventory
    3.         for (int i = 0; i < items.Count; i++) {
    4.             if (items [i]._ID == itemID) {
    5.                 // Subtract quantity
    6.                 items [i]._quantity = items [i]._quantity - amount;
    7.                 // Update inventory display
    8.                 for (int j = 0; j < itemSlots.Length; j++) {
    9.                     // Get slot script
    10.                     Item_Slot slotScript = itemSlots [j].gameObject.GetComponent<Item_Slot> ();
    11.  
    12.                     if (slotScript.itemID == items [i]._ID) {
    13.                         slotScript.itemQuantity = items[i]._quantity;
    14.                     }
    15.  
    16.                     if (items [i]._quantity == 0) {
    17.                         slotScript = itemSlots [j].gameObject.GetComponent<Item_Slot> ();
    18.  
    19.                         print ("Current item ID checking for: " + slotScript.itemID);
    20.  
    21.                         if (slotScript.itemID == items [i]._ID) {
    22.                             clearItemSlot (j);
    23.                             clearItemSlot (j + 1);
    24.                         }
    25.  
    26.                         items.Remove (items [i]);
    27.  
    28.                         //updateDisplay ();
    29.                     }
    30.                     //updateDisplay ();
    31.                 }
    32.                 //print ("Quantity of " + items [i]._name + "is now " + items [i]._quantity);
    33.                 // Delete item if it's quantiative value is 0
    34.                 /*if (items[i]._quantity == 0) {
    35.                     // Update inventorical display
    36.                     for (int j = 0; j < itemSlots.Length; j++) {
    37.                         // Get slot script
    38.                         Item_Slot slotScript = itemSlots [j].gameObject.GetComponent<Item_Slot> ();
    39.  
    40.                         print ("Current item ID checking for: " + slotScript.itemID);
    41.  
    42.                         if (slotScript.itemID == items [i]._ID) {
    43.                             clearItemSlot (j);
    44.                             clearItemSlot (j + 1);
    45.                         }
    46.                     }
    47.                     // Remove item
    48.                     items.Remove (items [i]);
    49.                 }*/
    50.             }
    51.         }
    52.  
    53.         updateDisplay ();
    54.     }

    clearItemSlot() function:
    Code (CSharp):
    1. public void clearItemSlot(int slotToClear) {
    2.         print ("Clearing slot: " + slotToClear);
    3.         Item_Slot slotScript = itemSlots [slotToClear].gameObject.GetComponent<Item_Slot> ();
    4.  
    5.         slotScript.itemQuantity = 0;
    6.         slotScript._quantityText.text = "";
    7.         slotScript.itemID = -1;
    8.         slotScript._imageObject.sprite = null;
    9.         slotScript._itemSprite = null;
    10.  
    11.         //updateDisplay ();
    12.     }

    updateDisplay() function
    Code (CSharp):
    1. public void updateDisplay() {
    2.         for (int i = 0; i < items.Count; i++) {
    3.             // Get their item script
    4.             Item_Slot slotScript = itemSlots [i].gameObject.GetComponent<Item_Slot> ();
    5.             // Set values
    6.             slotScript.itemQuantity = items [i]._quantity;
    7.             slotScript.itemID = items [i]._ID;
    8.             slotScript._itemSprite = items [i]._item.GetComponent<SpriteRenderer> ().sprite;
    9.         }
    10.     }

    inventory problem.gif
     
  2. Derpybunneh

    Derpybunneh

    Joined:
    Mar 26, 2015
    Posts:
    6
  3. JoshuaMcKenzie

    JoshuaMcKenzie

    Joined:
    Jun 20, 2015
    Posts:
    897
    theres a few issues in RemoveInventory()
    Line 17: is redunant from Line 10. you already have that slotscript from before no need to get the component again.

    Line 23: can cause an ArrayIndexOutOfBoundsException

    Line 26: this is likely the cause of your troubles. if you have ten slots and remove first slot (slot[0]), then 2nd slot will take its place (as slot[0]), but the variable "i" will be increment the next iteration of the loop, thus work on the 3rd slot (slot[1]) and skipping the 2nd slot (slot[0]). thus every time a slot is removed it skips checking the next slot
     
  4. Derpybunneh

    Derpybunneh

    Joined:
    Mar 26, 2015
    Posts:
    6
    Thanks for taking the time to look through all that code! You've pointed me in the right direction, but how would you suggest I fix this error? I've tried moving around the
    Code (CSharp):
    1. items.Remove (items [i]);
    line, but that doesn't really work. I'm thinking about maybe forgetting that line, and trying to re do the loop so that it works better. I appreciate your help!
     
    Last edited: Jan 3, 2017
  5. JoshuaMcKenzie

    JoshuaMcKenzie

    Joined:
    Jun 20, 2015
    Posts:
    897
    a common rule (specifically when using Foreach or IEnumerators) is that you shouldn't change the state of collection while you are iterating through it. such as removing an element in the same loop that you are processing it. typically you'd flag the items you want to remove and only remove them in a 2nd loop after you processed them all in the 1st loop

    assuming items is a List, you could try doing your processing normally (without any Remove) in the current loop and then after the outer loop finished make a "RemoveAll()" call. Interally RemoveAll will do this 2nd loop for you and figure out which items need to be removed based on the true/false expression you give it.
    Code (CSharp):
    1.  
    2. //** Remove Tile Code **//
    3.  
    4. //removes all items where this statement would be true
    5. // read as "remove any item with a quantity less than or equal to 0 from the items list"
    6. items.RemoveAll(item=> item._quantity <=0);
    7.  
    8. updateDisplay();
    9.