For Tooltips.. A Question About RequireComponent / IItemHolder

How come RequireComponent(typeof(IItemHolder) allows us to use the IItemHolder this way and not be forced to have to use its abstract member “GetItem()”?

namespace Game.UI.Inventories
{
    /// <summary>
    /// To be placed on a UI slot to spawn and show the correct item tooltip.
    /// </summary>
    [RequireComponent(typeof(IItemHolder))]
    public class ItemTooltipSpawner : TooltipSpawner
    {
        public override bool CanCreateTooltip()
        {
            InventoryItem item = GetComponent<IItemHolder>().GetItem();
            if (!item) return false;

            return true;
        }

        public override void UpdateTooltip(GameObject tooltip)
        {
            ItemTooltip itemTooltip = tooltip.GetComponent<ItemTooltip>();
            if (!itemTooltip) return;

            InventoryItem item = GetComponent<IItemHolder>().GetItem();

            itemTooltip.Setup(item);
        }
    }
}

Kind of baffling me and not really sure why it works that way.

I tried removing the RequireComponent section and then put ‘TooltipSpawner, IItemHolder’ however it forces me to implement the ‘GetItem’ member why is that?

[RequireComponent(typeof(T)) is a completely different concept from implementing the interface T. (I’m expressing this in generic terms because this concept applies broadly.

We’ll start with the implementing the interface:

public class MyClass : MonoBehaviour, ISomeInterface

This tells the compiler that MyClass is a descendant of ParentClass, and that MyClass directly implements the ISomeInterface class.

[RequireComponent(typeof(ISomeInterface))]
public class MyClass : MonoBehaviour

This tells Unity that any GameObject that has the MyClass attached must also have at least one component attached that implements the ISomeInterface. This will be a different component.

Now let’s make this specific to our ItemTooltipSpawner and IItemHolder:

    public interface IItemHolder
    {
        InventoryItem GetItem();
    }

Our interface specifies that any class that implements IItemHolder must have a public or qualified method InventoryItem GetItem()
In our InventorySystem we implement this class InventorySlotUI, EquipmentSlotUI, and ActionSlotUI. For example:

 public class InventorySlotUI : MonoBehaviour, IItemHolder, IDragContainer<InventoryItem>

In this case, the InventorySlotUI implements the IItemHolder with this method:

        public InventoryItem GetItem()
        {
            return inventory.GetItemInSlot(index);
        }

We want ItemTooltipSpawner to work with any of these three classes (or any other class you might create that has a tooltip you want to display, like a shop item in the Shops and Abilities course!). We also want to ensure that when we put an ItemTooltipSpawner on a GameObject, that it most certainly does have an IItemHolder implemented class on it. This is why we have

[RequireComponent(typeof(IItemHolder))]

RequireComponent is a special Unity only attribute that only makes sense with MonoBehaviours, i.e. things that are attached to GameObjects. It performs validiations when you try to remove a component from the GameObject… Unfortunately, it does not always automatically attach an item for you, specifically, since we’re requiring an Interface item, it doesn’t know which actual class you want to add… but assuming that the IItemHolder class is already there, it won’t let you remove that component until the ItemTooltipSpawner is removed.
You can test this by

  1. Creating an empty GameObject.
  2. Now on your empty GameObject, add an InventorySlotUI component.
  3. Try removing the component, and you can see that you can remove it normally.
  4. Add the InventorySlotUI component again
  5. Add an ItemTooltipSpawner
  6. Try removing the InventorySlotUI component. You’ll see that you can’t remove it.
  7. Remove the ItemTooltipSpawner
  8. Try removing the InventorySlotUI component. You’ll see that you can now remove it normally.
2 Likes

Meticulous and well thought out response Brian. This has widened my knowledge on the usage of Attributes and helped me to better understand abstract classes and interfaces.

RequireComponent attribute specifically, this was a rather new thing for me since never had to really implement them before, and it was confusing to me – as to why we didn’t implement the member explicitly like we always done throughout the courses but instead bypassed it with this attribute.

That’s really neat I never knew that because we had a component that already implements the member GetItem() from another class on said gameObject, that we didn’t have to also implement it through ItemTooltipSpawner. Wow still so much to learn…

Thanks a lot!

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.

Privacy & Terms