Blueprint Interface

From Augmotic Library

Blueprint Interfaces are an essential design tool for modularity and decoupling of your game logic. They allow cleaner interactions between multiple types of classes without needing to cast or tightly couple them together.

Interfaces take the form of abstract functions with no initial logic that can be implemented within a class to provide functionality on a per-class basis without the need to create long inheritance chains.

Use Cases

An Interaction System is one of the more popular features that will heavily benefit from using an interface.

You can place an Interaction interface on each object the player can walk up and use, such as a lever or a light switch. These two objects could do vastly different things, but from the player character's logic, all it needs to do is attempt to call the Interact function the interface defines. Each object can then implement its Interact function so the light switch can toggle some lights and lever open a door.

The key takeaway is that the character did not have to cast or know what type of object this was or even if it could be interacted with. Without an interface, you would need to either detect the class type and cast to access its Interact function or have all objects that can be interacted with derived from a base class. Both of those will bring pain and suffering later on once something needs to be changed and the code base has grown.

Creation

A new interface can be created by Right-clicking or using the Add button within the content browser and selecting Blueprint Interface.

The recommended naming convention from Unreal is to use a BI_ prefix. However, it is ultimately up to preference and the existing project's standards.

Editing

The editor for the interface is similar to the standard blueprint editor, except with more limitations and a different purpose. Instead of defining variables and implementing logic, this is only to describe the interface functions and their Inputs/Outputs.

Limitations

  • Functions Only
  • No Variables
  • No Logic Implementation

There is no limit on the number of functions that can be created for a single interface. However, too many starts leaning into code smell territory and probably has a better fit as multiple interfaces.

Implementation

Adding the interface to a blueprint class is straightforward. You can find the button to do so in the details window in the "Class Settings" tab.

Two lists can show the class's interfaces, "Implemented" and "Inherited."

  • Implemented: Interfaces that have already been added to one of the parent classes.
  • Inherited: Interfaces that have been added to this class.

Inherited interfaces can be added and removed using this menu. They will also automatically carry over to child classes without needing to do anything.

Defining

Once an interface is added to a class, its functions will appear in the "My Blueprint" tab. Modifying the interface and compiling causes the updates to appear in the blueprints used. Care must be taken when doing so, as this can cause issues if something uses a now-deleted function.

Double-clicking the function will either implement the event or open the tab of the function.
There are two ways the functions will appear depending on the types of parameters used.

Event Type
A function will be this type if there are no return parameters. It will add the event node to the main event graph when implemented.

Function Type
A function will be this type if any return parameters exist. It will open in a new tab to edit the implementation.

Usage

An interface function can be called in two different ways, as an interface message or a local function.

Local
Used when you want to call the interface function from within the same class it is implemented in, including a child class.
It can be found under the Call Function category when adding the node and will default to targeting self.

Execution is straightforward and will always succeed since it's implemented within the calling class.

Message
Used when you want to call the interface from another class. It can be found with a (Message) suffix in the add-node menu.
This version requires a Target input and has the envelope in the corner for easier identification.

Execution can fail the call silently. This is dictated by whether the target implements the interface or not. When this occurs, no errors are produced; the call just gets ignored.

Example

In this example, we are using an interface named Interaction, which defines an Interact function that will call a print string when used.
The player character will do a line trace from the camera's origin using its forward vector, then call Interact on the object that was hit by the trace.

The First Person Blueprint Content Pack is used in the example to provide a quick setup for the player character.

Interface

The Interaction interface consists of a function named Interact with no parameters.

Calling Class

Using the BP_Weapon_Component blueprint from the content pack, we can add the logic to shoot the line trace when pressing the shoot input. If an object is hit, Interact is called on that object.

Implementing Class

A new actor blueprint consists of a Cube component and implements the interface. It will print to the screen each time Interact occurs.

Expanding

Once you have the base functionality, you can implement the interface in many different classes, each with its way of handling an interact event. The power of an interface comes from carrying over common functionality without needing to know each class type concretely.

For instance, you could use the same interact function to toggle a light switch or pull a lever. Even with both classes having unique functionality, your player character only needs to send the interact message, and the implementing class handles the rest.