-1

Sorry, I know this is a dumb question but my brain needs some strong methods to help it gets through. I found a video on youtube about Interface => HERE the situation and codes were showed here. And My question:

 private void Update()
        {
            var nearestGameObject = GetNearestGameObject();
            if (nearestGameObject == null) return;
            if (Input.GetButtonDown("Fire1"))
            {
                var interactable = nearestGameObject.GetComponent<IInteractable>();
                interactable?.Interact();
            }
        }

In Update function => this line of code => var interactable = nearestGameObject.GetComponent<IInteractable>();
The GetComponent<IInteractable>(), what actually does it get ? get the interface ???? or get the Game Object, I have never seen an interface attached to the Gobj in the inspector before.

derHugo
  • 83,094
  • 9
  • 75
  • 115
Khoaoaoa
  • 23
  • 6
  • It gets the first matching component implementing that interface on that given `nearestGameObject` – derHugo Aug 23 '22 at 14:24
  • @derHugo so what exactly does this method return? cuz we can't create an instance from this interface so it will go inside the nearestGameObject script and create a virtual object of the interface ( just to easily imagine it ) and we can access all the methods and prop ( which the interface requests ) from it right? – Khoaoaoa Aug 23 '22 at 15:17
  • no .. it will return `IInteractable` ... which is an [`interface`](https://learn.microsoft.com/dotnet/csharp/language-reference/keywords/interface). The underlying object will be a reference to a component type that implements that interface .. as said the first one matching. It sounds to me there is a general misunderstanding of what an `interface` is in c# – derHugo Aug 23 '22 at 15:18
  • @derHugo Oh tks! i got it – Khoaoaoa Aug 23 '22 at 15:21
  • @derHugo but what is that misunderstanding ? – Khoaoaoa Aug 23 '22 at 15:25
  • well it sounded to me like you expect the GameObject to provide some sort of interface or create it add hock.. which of course it doesn't. The interface you get as a return value already **is** an instance of something existing. As you say yourself you can't create any instance of an interface ;) That's also the reason why Unity allows interfaces as type for`GetComponent` but has a hard type restriction for `AddComponent` ;) – derHugo Aug 23 '22 at 15:27
  • @derHugo Oh so according to what you said, there is some magic behind the scene that can make an instance of a type that behaves like the interface and has all of its information and return it to me. But as usual, I can't create an instance of the interface so I can't use `AddComponent` right ? – Khoaoaoa Aug 23 '22 at 15:36
  • No. I meant to say the contrary ;) Again: The instance already exists. It has to, otherwise `GetComponent` simply doesn't find any and returns `null`. The component has to be already added to the GameObject previously, either via the Inspector or on runtime ... but if via code hen it can only have been added as the actual implementing type – derHugo Aug 24 '22 at 06:41

2 Answers2

1

I see there is still some confusion for what exactly this is good for.

So I decided to extend on this answer and my comments a bit with a practical example.

Let's say you have the given interface e.g.

public interface IInteractable
{
    void Interact();
}

now you can have as many different implementations as you wish. An interface is just a kind of template for a type and tells the implementing type that there a certain members it needs to provide. And it tells the user of such an interface (like in your case the code you shared) that whatever actual type is returned - we can be sure there are certain members implemented by it we can use.

For example there could be one that simply destroys itself once you interact with it

public class DestroyInteractable : MonoBehaviour, IInteractable
{
    public void Interact()
    {
        Destroy(gameObject);
    }
}

Or why not one that moves e.g. for triggering a platform

public class MoveInteractable : Monobehaviour, IInteractable
{
    [SerializeField] Rigidbody _rigidbody;

    [SerializeField] float moveDuration = 1f;
    [SerializeField] Vector3 targetPosition;

    public void Interact()
    {
        StartCoroutine(Move());
    }

    IEnumerator Move()
    {
        yield return new WaitForFixedUpdate();

        var startPosoition = _rigidbody.position;
        for(var timePassed = 0f; timePassed < moveDuration; timePassed += Time.deltaTime)
        {
            _rigidbody.MovePosition(Vector3.Lerp(startPosition, targetPosition, timePassed / moveDuration));

            yield return new WaitForFixedUpdate();
        }
    }
}

ETC ... You can do what ever you want to trigger in your interactable objects.


And now we come to your shared code.

Allow me a small but important excurs at this point.

There is one huge flaw: NEVER use ?. operator on UnityEngine.Object! (see Why does C# null-conditional operator not work with Unity serializable variables?)

In general it should rather be

if(nearestGameObject.TryGetComponent<IInteractable>(out var interactable))
{
    interactable.Interact();
}

Now what does this do?

It searches for any component type on the given GameObject that implements the IInteractable interface. If it finds one it returns a reference to that found (which means already existent) component as IInteractable. If none is present it returns null.

Your code doesn't care at all what the exact actual class type is, since it doesn't need to know. For itself to work all it needs to know is that there is a method called Interact() it can call. Whatever happens after this call is not our business and doesn't matter to us at this point.

Now you see why this is so powerful: With a single controller on your player object you can now interact with all the different types of IInteractble objects, each can define a different reaction to your interaction - you don't have to care at all.

I hope that spreads a bit more light into not only what it does but why it is useful.

derHugo
  • 83,094
  • 9
  • 75
  • 115
0

An interface cannot be instantiated. Instead, it will get the interactable object which is an instance of a class that implement IInteractable.