Alex πŸ¦… Profile picture
Feb 20, 2024 β€’ 20 tweets β€’ 6 min read β€’ Read on X
Over the years, I've worked on a wide range of projects from small indie ideas to AAA games.

Here is how I would build an interaction system from scratch in Unreal Engine if I were to start a new project today.

A thread πŸ§΅πŸ‘‡πŸΌ
1/17 General Philosophy

The main goal is to make an architecture that's easy to maintain. To achieve this we are going to go for simple bare bones solutions.

We are not going to develop a one-size-fits-all solution, instead, we aim to keep complexity to a minimum. Image
2/17 Limiting inheritance

Let's take the example of a door.

If we have an Interactable base class, the next logical step is to create a Door class inheriting from it and add the rotation logic.

This way the user can open the door by interacting with it.Image
3/17 Limiting inheritance

If we need a broken door (BrokenDoor) that can be opened only by an explosion, now we have to:

β€’ Copy-paste the rotation logic to a new component
or
β€’ Add the option to disable the interaction - which makes inheriting from Interactable uselessImage
4/17 Interfaces

Interfaces are a great way to ensure that classes of unrelated types have common functionality implemented.

They are a solid choice, but in the context of Unreal, they have some limitations (e.g.: complicated setup to expose configurable per-object properties). Image
5/17 Interfaces

For this reason, we are going to avoid this time around and go with actor components.

(However, for other systems like an Events System, where we want to broadcast events to both actor-based components and widgets, they are the go-to choice).
6/17 What are we going to do?

This time around, we are going to go for an ActorComponent. This way the component can be added when actors need to be interacted with.

We are going to focus on C++ mainly, but similar delegates & functions can be exposed to blueprints.
7/17 The InteractableComponent

β€’ OnInteract - executed upon interacting, e.g.: rotate the door 90 degrees
β€’ CanInteract - performs additional tests before interaction, e.g.: does the user have the required key
β€’ TryInteract - called when the user wants to interact Image
8/17 InteractableComponent implementation

In the component's implementation, we have 2 important aspects:
β€’ if the OnInteract delegate is not bound, we are going to raise a warning
β€’ if the CanInteract delegate is not bound, the user is always allowed to interactImage
9/17 How to trigger interactions

To allow the player to interact with objects, we need to give him the ability to call the TryInteract function.

To achieve this, we are going to add an InteractorComponent component to the player which will scan for nearby interactable actors
10/17 The InteractorComponent

This component will do a Sweep in front of the player to check for interactables every frame.

We have a few configurable properties which we will cover as we go over their usage. Image
11/17 InteractorComponent Implementation

β€’ Constructor: enables the component's tick function
β€’ BeginPlay: binds the user's "Interact" input to the PerformInteraction function
β€’ Tick: runs the UpdateInteractionCandidates each frameImage
12/17 UpdateInteractionCandidates

This function performs a trace with debugging data - which we will live view.

Afterward, we look for potential interaction targets (you can sort them based on distance, but for simplicity's sake, we are just going to go for the first hit). Image
13/17 PerformInteraction

The hard work has already been done, here we can just check if we currently have a valid target and try interacting with it. Image
14/17 Player setup

Now that all the code has been laid out, we will begin adding our new components starting with the player's Interactor. Image
15/17 Interactable setup

Next up, we will add the Interactable component to the rifle.

(This project started from the first-person C++ template). Image
16/17 Interact input setup

And finally, we will add the same Interact input we assigned in the code and bind it to the "E" key.

(As pointed out in the warning below, we should use the Enhanced Input system, but that would result in a way longer thread). Image
17/17 Live Demo

Here we have a live demo of the interaction system with the additional debug drawings.
That's all for today!

If you learned something new:

1. Follow me @OutoftheboxP for more of these
2. Retweet the tweet below to share it with your fellow developer friends.

Since this thread went way over my expectations already, here is a friendly remind Quick Actions is free on the Unreal Marketplace:

unrealengine.com/marketplace/en…

β€’ β€’ β€’

Missing some Tweet in this thread? You can try to force a refresh
γ€€

Keep Current with Alex πŸ¦…

Alex πŸ¦… Profile picture

Stay in touch and get notified when new unrolls are available from this author!

Read all threads

This Thread may be Removed Anytime!

PDF

Twitter may remove this content at anytime! Save it as PDF for later use!

Try unrolling a thread yourself!

how to unroll video
  1. Follow @ThreadReaderApp to mention us!

  2. From a Twitter thread mention us with a keyword "unroll"
@threadreaderapp unroll

Practice here first or read more on our help page!

More from @OutoftheboxP

Jul 4
A lot of developers use UDeveloperSettings to quickly expose configurable variables in the Project Settings or Editor Preferences.

However, there is a slightly cooler option you should know about.

Here is a breakdown of both and how to use them.

A thread 🧡 Image
1/11 What is UDeveloperSettings

In a nutshell, it is a utility class which automatically registers the class with the settings module.

To be honest, this is not groundbreaking. We can call FSettingsModule::RegisterSettings manually. But it's a nice quality of life feature. Image
2/11 Accessing UDeveloperSettings

For most use-cases, you can access the data via GetDefault, which is read-only (const).

However, when you need to write that, you can use GetMutableDefault which allows you to mutate the default values.

(P.S.: Remember to call SaveConfig) Image
Read 13 tweets
Jul 2
Is Unreal Engine moving super slow for you?

Here is how you can use FScopedSlowTask to make it more enjoyable.

A thread 🧡
1/11 What is FScopedSlowTask ?

Is an editor-utility class that helps developers display loading bars when creating editor tools.

It's super easy to add to your existing logic and makes the waiting much better for your end users. Image
2/11 How does FScopedSlowTask work?

It takes advantage of the object's lifetime and automatically initializes the task's data in the constructor (you still have to show it by using MakeDialog).

And destroys the pop-up once the object is out of scope (e.g. function ended). Image
Read 13 tweets
Jan 8, 2024
Here is how to create your own editor mode inside Unreal Engine.

Extend the editor with custom tools like the Landscape mode tailor to your own project.

A thread πŸ§΅πŸ‘‡πŸΌ Image
1/4 Create the EdMode subclass

The EdMode subclass is responsible for registering and initializing the mode. It provides access to crucial virtual functions such as UEdMode::Enter & UEdMode::Exit which are triggered selecting and leaving the edit mode. Image
2/4 Create the ModeToolkit subclass

The Toolkit is responsible for creating the UI panel. It allows you to fully customize the panel with custom widgets are leverage the built-in DetailsView panels. Image
Read 6 tweets
Jan 7, 2024
Here is how you can run custom logic during the engine initialization from your own modules.

A thread πŸ§΅πŸ‘‡πŸΌ Image
Registering callbacks is usually straight forward:

You get a reference to an object, access the delegate and add your callback.

However things can get tricky when it comes to engine initialization.
The main problem is you risk registering your custom logic too late - after the delegate has been fired.

To avoid this kind of problems, Unreal has FDelayedAutoRegisterHelper which gives access to a bunch of critical delegates and automatically registers the callback.
Read 8 tweets
May 1, 2023
Is your game struggling with performance?

Here is how to run your Unreal C++ code asynchronously to avoid bottlenecks.

A thread πŸ§΅πŸ‘‡πŸΌ Image
A little bit of context:

I am working on integrating @Tolgee_i18n localization tools inside Unreal Engine.

One of problem I've encountered is the performance hit coming from refreshing the Localization Manager resources.

A single call would take 450ms and drop the FPS to 2. Image
1. Investigating & diagnosing the issue

The first step we need to take is to add as many TRACE_CPUPROFILER_EVENT_SCOPE in performance-heavy code. This will measure the impact of the function's execution.

As a general rule of thumb, when in doubt, always add more. Image
Read 8 tweets
Mar 4, 2023
How to write and refactor code without introducing any bugs.

Write your first Unreal Engine test today in 6 steps using Rider.

A thread πŸ§΅πŸ‘‡πŸΌ
First off, let's discuss what automation tests are and what their purpose is:

Automated Tests are a controlled environment where you can verify the outcome of a piece of code against the expected result. They ensure our code behaves as expected while developing/refactoring it.
Step 1: Create the test class

1. Navigate to the module you want to add the test file to inside Rider.
2. Right-click the module project
3. Go to Add β†’ Unreal Test Class Image
Read 11 tweets

Did Thread Reader help you today?

Support us! We are indie developers!


This site is made by just two indie developers on a laptop doing marketing, support and development! Read more about the story.

Become a Premium Member ($3/month or $30/year) and get exclusive features!

Become Premium

Don't want to be a Premium member but still want to support us?

Make a small donation by buying us coffee ($5) or help with server cost ($10)

Donate via Paypal

Or Donate anonymously using crypto!

Ethereum

0xfe58350B80634f60Fa6Dc149a72b4DFbc17D341E copy

Bitcoin

3ATGMxNzCUFzxpMCHL5sWSt4DVtS8UqXpi copy

Thank you for your support!

Follow Us!

:(