Loop through multiple parents and their children

So Im making some inventory coding and Im trying to stock gameobjects into an array.
7999167--1028403--Capture.PNG
Here is how it goes. I need to add each Panel’s button into a single gameobject array such as the following example.
7999167--1028409--Capture2.PNG
This process was simple because it just needed to loop into the Content gameobject and get all the Panel which all share the same parent.

But with the buttons I need to get into the parent, loop the children, get the button, then get out and get into the following parent and It’s making my head overheating…

This code loop the content gameobject to get the panel:

slotsMisc = new GameObject[miscContainer.transform.childCount];

        for (int i = 0; i < miscContainer.transform.childCount; i++)
        {
            slotsMisc[i] = miscContainer.transform.GetChild(i).gameObject;   
        }

I think It’s all about how I loop them.

I don’t think I quite understand, what are you trying to do with these buttons?

Might be easier to just grab all the “Button” components under your panel and add their gameObjects, e.g.:

        var buttons = miscContainer.GetComponentsInChildren<Button>();
        for (int i = 0; i < buttons.length; i++)
        {
            slotsMisc[i] = buttons[i].gameObject;
        }

That way the depth of the hierarchy doesn’t matter.

Of course, this won’t work if you have other buttons under that panel that you DON’T want to include.

2 Likes

I’m going to second the question of: what are you planning to do with this array? I’d venture to guess there’s a better way to achieve whatever you’re trying to achieve than creating this array.

I agree, I am aware that what Im trying to achieve by puttin these buttons in an array is questionable But I lack logic and for the small amount of solution I can gather by myself (without watching tutorial) it turns out to be chaotic but I always end up polishing this complete chaos so Im just gonna do what I was planning to do and then see if there is a smoother solution. If you need details, It’s a scroll view inventory
7999842--1028568--zezezeze.PNG
And what Im trying to do is to add to my game an item selection, when you click on an item panel it returns the icon and the description of its item into the right window. So I added a button into my panel prefab and I want to stock the item picked up in the button as well. In this way, If I click the button I could return the item and get its icon and description.

Typically when I have complex buttons (I.E. more data to change than just the button’s onClick) I create a MonoBehaviour that I can shove on the parent of each node, in your case, it’ll be for each item in the inventory, and have that manage that node only.

Example:

public class UpgradeNode : MonoBehaviour
{
    [SerializeField]
    private Image icon;
    [SerializeField]
    private GameObject cover;

    public void SetOwned()
    {
        cover.SetActive(true);
    }

    public void SetImage(Sprite sprite)
    {
        icon.sprite = sprite;
    }
}

Take this upgrade node class, it is placed every UpgradeNode in the hierarchy that I have stored in a scrollable list, just like you. It manages itself though, so you can just call UpgradeNode.SetImage() to set it’s image. You could go even broader and just create and call UpgradeNode.UpdateNode() and pass in some kind of Upgrade that already contains a bunch of information so that your UpgradeNode can parse it.
Ex:

    public void UpdateNode(Upgrade upgrade)
    {
        icon.sprite = upgrade.sprite;
        cover.SetActive(upgrade.owned);
        ...
    }

I find this to be a much better approach in these situations so you don’t have a foreach loop with a tonne of GetChild() or GetComponentsInChildren() calls. Simply make a prefab and assign all your variables to an object, instantiate your prefab when you need it and call UpdateNode() to update it, nice and easy.

1 Like

Here’s another option if you don’t mind a little scripting. It’s a little involved so I’ve cut it down to some pseudo code, hopefully it’s enough to give you some ideas.

Have a manager script for each of the panels, on initialisation grab the UI elements and put them in a new manager. Create another manager that manages them.

This is the panel manager:

public class ItemSlotManager
{
    private UiPanel panel;
    private UiIcon icon;
    private UiText text;
    private UiButton button;

    public ItemSlotManager(UiPanel panel, UiIcon icon, UiText text, UiButton button)
    {
        this.panel = panel;
        this.icon = icon;
        this.text = text;
        this.button = button;
    }

    public void AddItem(ItemDetail itemDetail)
    {
        icon.Sprite = itemDetail.IconSprite;
        text.text = itemDetail;
        button.name = itemDetail;
        panel.gameObject.SetActive(true);
    }

    public void RemoveItem()
    {
        panel.gameObject.SetActive(false);
    }
}

And the manager to look after them:

public class ItemSlotsManager
{
    List<ItemSlotManager> slotManagers = new List<ItemSlotManager>();

    public void AddItem(ItemDetail itemDetail)
    {
        ItemSlotManager slotManager = FindFreeSlot();
        slotManager.AddItem(itemDetail);
    }

    public void RemoveItem(uint slotId)
    {
        ItemSlotManager slotManager = FindSlot(slotId);
        slotManager.RemoveItem();
    }

    private ItemSlotManager FindSlot(uint slotId) { }

    private ItemSlotManager FindFreeSlot() { }

    public void CreateItemSlotManager(UiPanel panel, UiIcon icon, UiText text, UiButton button )
    {
        slotManagers.Add(new ItemSlotManager(panel, icon, text, button));
    }

    public void Initialise()
    {
        UiPanel[] panels = GameObject.FindObjectsOfType<UiPanel>();

        foreach (UiPanel panel in panels)
        {
            UiIcon icon = FindIcon();
            UiText text = FindText();
            UiButton button = FindButton(); // needs an onClick listener

            CreateItemSlotManager(panel, icon, text, button);
        }

    }
}

You’ll need to set up the button listener for the button, a simple way to have the button name as a parameter so you know which button was clicked.

I’m using something similar and haven’t had any issues with it.