最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

c# - Why am I returning the wrong hierarchy level for the children? - Stack Overflow

programmeradmin0浏览0评论

Using unity, I have a canvas with panels in it. There are two separate panels (hotbar, inventory), each with panels in it (a slot for the hotbar/inventory). I am trying to use the GetComponentsInChildren function to add all of these slots to an array, then edit their sprites from there. However, rather than getting all the children in the hotbar panel, it is returning the actual hotbar panel.

Here is the code:

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

public class InventoryDisplay : MonoBehaviour
{
    public Transform[] hotbar;
    public Transform[] inventoryUI;
    [SerializeField]
    public Inventory inventory;
    public GameObject hotbarObject;
    public GameObject inventoryObject;
    void Start()
    {
        hotbar = hotbarObject.GetComponentsInChildren<Transform>();
        inventoryUI = inventoryObject.GetComponentsInChildren<Transform>();
    }

    void Update()
    {
        InventoryCheck();
    }
    void InventoryCheck()
    {
        for (int i = 0; i < hotbar.Length; i++)
        {
            if (inventory.items[i] != Resources.Load<Item>("Items/Empty"))
            {
                hotbar[i].GetComponent<SpriteRenderer>().sprite = inventory.items[i].sprite;
            }
            else
            {
                print(hotbar[i]);
                hotbar[i].GetComponent<SpriteRenderer>().sprite = null;
            }
        }
        for (int i = hotbar.Length; i < inventoryUI.Length; i++)
        {
            if (inventory.items[i] != Resources.Load<Item>("Items/Empty"))
            {
                inventoryUI[i].GetComponent<SpriteRenderer>().sprite = inventory.items[i].sprite;
            }
            else
            {
                inventoryUI[i].GetComponent<SpriteRenderer>().sprite = null;
            }
        }
    }
}

The important part here is line 16, where I would expect it to give all the children under the hotbarObject, but it seems to be returning all children in the main panel.

Here is a screenshot for some visual help:

Screenshot of the unity screen

Any ideas on why it's functioning like this?

Using unity, I have a canvas with panels in it. There are two separate panels (hotbar, inventory), each with panels in it (a slot for the hotbar/inventory). I am trying to use the GetComponentsInChildren function to add all of these slots to an array, then edit their sprites from there. However, rather than getting all the children in the hotbar panel, it is returning the actual hotbar panel.

Here is the code:

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

public class InventoryDisplay : MonoBehaviour
{
    public Transform[] hotbar;
    public Transform[] inventoryUI;
    [SerializeField]
    public Inventory inventory;
    public GameObject hotbarObject;
    public GameObject inventoryObject;
    void Start()
    {
        hotbar = hotbarObject.GetComponentsInChildren<Transform>();
        inventoryUI = inventoryObject.GetComponentsInChildren<Transform>();
    }

    void Update()
    {
        InventoryCheck();
    }
    void InventoryCheck()
    {
        for (int i = 0; i < hotbar.Length; i++)
        {
            if (inventory.items[i] != Resources.Load<Item>("Items/Empty"))
            {
                hotbar[i].GetComponent<SpriteRenderer>().sprite = inventory.items[i].sprite;
            }
            else
            {
                print(hotbar[i]);
                hotbar[i].GetComponent<SpriteRenderer>().sprite = null;
            }
        }
        for (int i = hotbar.Length; i < inventoryUI.Length; i++)
        {
            if (inventory.items[i] != Resources.Load<Item>("Items/Empty"))
            {
                inventoryUI[i].GetComponent<SpriteRenderer>().sprite = inventory.items[i].sprite;
            }
            else
            {
                inventoryUI[i].GetComponent<SpriteRenderer>().sprite = null;
            }
        }
    }
}

The important part here is line 16, where I would expect it to give all the children under the hotbarObject, but it seems to be returning all children in the main panel.

Here is a screenshot for some visual help:

Screenshot of the unity screen

Any ideas on why it's functioning like this?

Share Improve this question asked Jan 29 at 13:43 ShogShog 137 bronze badges
Add a comment  | 

1 Answer 1

Reset to default 1

GetComponentsInChildren also returns components attached to the object you're running it on, not just the object's children.

From the Unity Docs for GetComponentsInChildren:

Gets references to all components of type T on the same GameObject as the component specified, and any child of the GameObject


So there's multiple things you could do here. You can either:

  1. Filter out the first element of each array (which would be the Transform of the Hotbar/InventorySlots object); either by starting the loops at i = 1 or removing the element outright through a List.

    for (int i = 1; i < inventoryUI.Length; i++) {
        // starting from 1 skips the parent's transform
        ...
    }
    

    Make sure to compensate for the fact that the array would be 1 item longer than there are valid slots; you would have to index based on i - 1, and you would have to start your second loop with i = hotbar.Length + 1 (and index with i - 2 in the inventory UI's loop).

  2. You can use the Transform.GetChild method (along with Transform.childCount) on the panels' transforms to explicitly get the children.

    for (int i = 0; i < inventoryObject.transform.childCount; i++) {
        // get the transform of the children
        Transform x = inventoryObject.transform.GetChild(i);
        ...
    }
    

or, the most performant option:

  1. Create a new component to your script that will handle populating the item's graphics (instead of having the InventoryDisplay do it directly for the slot), so GetComponentsInChildren wouldn't return the parent object (since ItemSlot wouldn't be attached to the parent). This would also allow you to store cached references to the item slots' SpriteRenderers, which is ideal as GetComponent<T> is relatively slow.

    public ItemSlot[] hotbar;
    public ItemSlot[] inventoryUI;
    // ...
    void Start()
    {
        hotbar = hotbarObject.GetComponentsInChildren<ItemSlot>();
        inventoryUI = inventoryObject.GetComponentsInChildren<ItemSlot>();
    }
    // ...
    void InventoryCheck() {
        for (int i = 0; i < hotbar.Length; i++) {
            int itemIndex = i;
            hotbar[i].UpdateGraphics(inventory.items[itemIndex]);
        }
        for (int i = 0; i < inventoryUI.Length; i++) {
            int itemIndex = i + hotbar.Length;
            inventoryUI[i].UpdateGraphics(inventory.items[itemIndex]);
        }
    }
    

    ItemSlot.cs:

    public class ItemSlot : MonoBehaviour {
        [SerializeField] private SpriteRenderer sRenderer;
        [SerializeField] private Item emptyItem;
    
        public void OnValidate() {
            if (!sRenderer) sRenderer = GetComponent<SpriteRenderer>();
        }
    
        public void UpdateGraphics(Item item) {
            Sprite sprite = null;           
            if (item && item != emptySlot) {
                sprite = item.sprite;
            }
    
            sRenderer.sprite = sprite;
        }
    }
    
发布评论

评论列表(0)

  1. 暂无评论