Inventory breaks when removing items

I am currently working on an inventory script to hold items like keys in my game. I have it all set up where items can be picked up, and are basically added to a list of items I can cycle through with “Q.”

This works well. However I have ran into issues when removing the objects from the list, i.e. using the key and removing it from the player’s inventory.

If I have a set up like: Barehands, Key1, Key2, Key3, and start “deleting” the keys starting with 3, then 2, etc. it works perfectly. Key three gets deleted and the game recognizes I am now holding Key2, since it is now the last one in the list.

However, with the same setup, I experience an issue when attempting to use the keys in the opposite direction. When holding: Barehands, Key1, Key2, Key3, when I delete Key1, instead of Key2 becoming the active item in the player’s hand, it glitches. Usually, the result is the key being deleted, but no new item being “selected,” furthermore, when I press “Q” again, it seems to either select Barehands (first in list) as the active item, or skip Key2 and make Key3 active, although using Key3 deletes Key2 from the list, etc.

I don’t usually like to just throw code walls up and ask for a solution but I have been banging my head against the wall all week. I believe the original item-switching mechanism was from a Brackeys tutorial and was modified for my game, in addition to random things inside the DestroyItem() function in hopes of me solving it myself. Any ideas on how to fix this issue?

My Inventory Script:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Inventory : MonoBehaviour
{
    public GameObject[] items; //Held Items

    public GameObject heldItems;
    private ItemSwitching itemSwitching; //Tracking of Item Slot Number

    public GameObject currentHeldItem; //current Item in hand
    public GameObject destoryThis;


    // Start is called before the first frame update
    void Start()
    {
        heldItems = GameObject.Find("HeldItems");
        itemSwitching = heldItems.GetComponent<ItemSwitching>();
    }

    // Update is called once per frame
    void Update()
    {
        if (itemSwitching.selectedItem != 0)
        {
            currentHeldItem = items[itemSwitching.selectedItem]; //If not barehanded, make currentHeldItem the current item in hand
        }
        else
        {
            currentHeldItem = null; //else make it nothing
        }

        if (Input.GetKeyDown(KeyCode.L))
        {

            DestroyItem();
        }

        destoryThis = currentHeldItem;

    }

    public void updateInventory()
    {
        //Move every item down, filling all possible slots first.
        int nextFree = 0;
        for (int i = 0; i < items.Length; i++) // whole inventory list
        {
            GameObject ivi = items[i]; // temp copy
            if (ivi == null) continue;
            //print("copying " + ivi.name + " from " + i + " to " + nextFree);
            items[i] = null; // so we don't have extra copies
            items[nextFree] = ivi; // this may copy over the same spot, which is fine
            nextFree++;
        }

}

    public void DestroyItem()
    {
       
        currentHeldItem = null;
        Debug.Log(destoryThis);
        Destroy(destoryThis);

        items[itemSwitching.selectedItem] = null; //Make Inventory Slot Empty
       
        itemSwitching.selectItem();
        items[itemSwitching.selectedItem].SetActive(true);
        itemSwitching.selectedItem++;

        updateInventory();

    }

My Item Switching Script:

using UnityEngine;

public class ItemSwitching : MonoBehaviour
{
    public int selectedItem = 0;
    public GameObject currentlyHeldItem;

    // Start is called before the first frame update
    void Start()
    {
        selectItem();
    }

    // Update is called once per frame
    void Update()
    {
        int previousSelectedItem = selectedItem;

        if (Input.GetKeyDown(KeyCode.Alpha1))
        {
            selectedItem = 0;
        }

        if (Input.GetKeyDown(KeyCode.Alpha2) && transform.childCount >= 2)
        {
            selectedItem = 1;
        }

        if (Input.GetKeyDown(KeyCode.Q))
        {
            if (selectedItem >= transform.childCount - 1)
               selectedItem = 0;
            else
                selectedItem++;
        }

        if (!Input.GetKeyDown(KeyCode.Q) && selectedItem >= transform.childCount )
        {
           
                selectedItem = transform.childCount - 1;
           
        }

        if (previousSelectedItem != selectedItem)
        {
            selectItem();
        }
    }

    public void selectItem()
    {
        int i = 0;
        foreach (Transform item in transform)
        {
            if (i == selectedItem)
            {
                item.gameObject.SetActive(true);
                Debug.Log(item.gameObject.name);
                currentlyHeldItem = item.gameObject;
            }
            else
            {
                item.gameObject.SetActive(false);
            }
               
                i++;
        }
    }
}

The deletion function is called from a third script that just checked if iyemSwitch.currentlyHeldItem is the required object (key for door player is trying to open), and calls the DestroyItem() function in the inventory script.

And this is why I am always hesitate to post on the forum.

After messing around a bit more I tried creating a new function inside the itemSwitching script.

public void NextItem()
    {
        if (selectedItem >= transform.childCount - 1)
        {
            Destroy(currentlyHeldItem);
        }else
        {
            //Debug.Log("Next Item");
            Destroy(currentlyHeldItem);
            selectedItem++;
            selectItem();
        }
    }

Now instead of making the script that is deleting the item switch, I am making the script that is switching the items delete it. With this the script works as intended, and now in the raycast I simply call NextItem() and it will do the work. Meaning I can completely remove the DestroyItem() function and all the hideous code inside.

Why are lines 71 and 72 in DestroyItem()? It looks like you already call selectItem() on line 70 to activate the appropriate object.

edit: beat me to it! :stuck_out_tongue:

But yeah, the takeaway here is to try to encapsulate as much as you can: the DestroyItem function shouldn’t care about how to select something. That’s selectItem’s job!

1 Like