UNITY TIP: Utilize C# interfaces to simplify development
When I first started programming I never quite understood the benefits of using interfaces.
Over time this however has changed. And they have been proven to be quite useful in Unity.
What is an interface?
The way I would explain it is that a interface is a addition for functionality within a class or struct.
When you add it, you are required to add the methods that the interface contains.
The benefit of this is that multiple classes can use the same interface,
This creates common functionality which can be called that doesn’t depend on the object type.
Microsoft documentation on C# interfaces
DotNetPerls has a practical explaination.
/// <summary> | |
/// Gets called from a health component if it has taken damage | |
/// </summary> | |
public interface IDamageable : IHealthInterface | |
{ | |
void OnDamaged(HealthInfo info); | |
} |
Obtaining references to Iinterfaces in Unity 3D
In Unity it is possible to get interface references calling GetComponent<T>()
Since it is possible for multiple scripts to implement a interface, I would always use GetComponents<T>().
For the example above you would call GetComponents<IDamageable>() and that will return all references to implementations of the interface at the root of the Game Object. You can cast the object to a interface and the other way around by calling >object< as >type<.
(flashOnHitComponent as IDamageable). You can find more information about casting here
The pattern I apply using interfaces in Unity 3D
Usually I create a script that is responsible for obtaining and notifying all interfaces on a object.
For example I wll use the Health component from Health Pro & Effects, which will get all health related interface references during editor-time.
Such as IKIllable, IDamageable, IReviveable. And during run-time it will notify all those components based on the implemented interfaces.
The benefit of this pattern is, I do not longer have to think about creating references for the Health script. No need for delegates, or UnityEvents.
Why use Interfaces?
Interfaces can make your project more complex to understand, since you cannot directly see how they are implemented if you don’t know the design. Altough the benefits are great, since it will greatly simplify your code. If you name your interfaces correct you will immiedtly see the responsibilities for a class based on it’s interfaces and class name.
In the case of a closed source engine like Unity it can also be beneficial to use interfaces when inheritance is impossible.
A example of this is the TileBase class, from the new tilemap system in Unity. This class is inherits from ScriptableObject.
If you wanted to make a class that applied to both TileBase and ScriptableObject, that would be impossible to do through inheritance. Since you cannot modify any of those classes. A interface would make it possible for both types to have shared functionality.
Example – Interactable objects
In the sample project you can find below I have given a example of how I’ve used interfaces to add functionality to a class.
The pillar objects contain a Interactable component and a component that scales them up once they are focused by the player.
And a component that destroys the pillar once interact has been called by the player.
I recommend looking through the repository map. The way it works is relatively straightforward.
- Interactor – Checks for collisions with Interactables. And prioritizes them based on distance and angle.
- Interactables – Get all components that implement IInteractable interface, and notifies them
- Player – Has examples of retrieving callbacks and calling the Interactor.
- Interact Actions – Example components of actions that get called through interface