While our game may be running without any issues in the editor or even in…
Using Unreal Motion Graphics (UMG) with C++
In this post we’re going to see how we can utilize the UMG menu of UE4 using C++. For this project we will create a simple UI menu that will update every time we collect a new item.
Here is the end result:
Getting Started
In order to get started, create a C++ project template (in my case I created a Third Person Template but you can choose otherwise). When Visual Studio loads, locate the following files which have the same name as your project (my project’s name is TPBlogProject so your files names might differ) :
Inside the .Build.cs file edit the following line from:
1 |
PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore" }); |
to:
1 |
PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "UMG", "Slate", "SlateCore" }); |
Save and close that file.
When you’re done with that, open up the header file which has the same name as your project and add the following includes:
1 2 3 4 5 |
#include "Runtime/UMG/Public/UMG.h" #include "Runtime/UMG/Public/UMGStyle.h" #include "Runtime/UMG/Public/Blueprint/UserWidget.h" #include "Runtime/UMG/Public/Slate/SObjectWidget.h" #include "Runtime/UMG/Public/IUMGModule.h" |
Save and close that file.
Make sure you followed the above steps, otherwise your code will not compile.
Now we are ready to create our UI Widgets which are based on C++.
Before we do that, let’s take a step back and have an overview of what we’re going to create and what we need. As mentioned above, we’re going to create a character that collects items. Each time we collect an Item our UI will display a list with the names of the items we’ve collected so far. To do that, we need the following classes:
- A Collectible class, the instances of this class will be the items that we’re going to collect.
- A UWidget class – essentially our UI.
- A Character that will collect items.
- A Player Controller which will be responsible for the communication between our UI and our Character
- A Game Mode class which will be used only to tell the editor that in the default map we need our own mode in order to tie the player controller that we’re going to create with the default character.
So, let’s get started!
Creating our UWidget class
The UWidget class will be the base class for our UI which later will be a Widget Blueprint. The following screenshot shows which class to choose as parent in order to add a UWidget class (I named my class CollectiblesUI):
When visual studio is done with compiling, open up the header file of your newly added class and add the following property and functions:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
protected: /*Responsible for adding the ItemToAdd to our UI*/ UFUNCTION(BlueprintImplementableEvent, Category = UI) void AddItemToUI(); /*The next item that is going to get added inside our UI*/ UPROPERTY(BlueprintReadOnly) FText ItemToAdd; public: /*Adds the name of the item we collected inside our UI by using our AddItemToUI protected function*/ void AddItemToUI(FText ItemName); |
When you’re done with that, switch to your source file, and add the following implementation of the AddItemToUI function:
1 2 3 4 5 |
void UCollectiblesUI::AddItemToUI(FText ItemName) { ItemToAdd = ItemName; AddItemToUI(); } |
That’s it, we’re done with the C++ code of our UI. Save and compile your code. Then, switch to your Editor and create a new Blueprint class which will be based in the following class:
You may notice that I have already created a Collectible class. Don’t worry, right after we’re done with the UI I will explain what to do. In this case, I named my Blueprint as UW_Collectibles. When you open up your blueprint, you will notice that we have created a Widget which is based on our C++ class.
Inside your widget, I created a Vertical box, which I marked as a Variable – this is essential don’t forget this step, and inside I added a simple Text:
When you’re done with that, switch to your graph, and override the protected AddItemsToUI function like so:
In order for the Construct Text to appear, right click somewhere in the empty space of your Blueprint and select the “Construct Object from Class”. Then, inside the Class field, select the TextBlock class.
That’s it- we’re done with our UI. Let’s create our Controller!
Creating our Controller
Create a new C++ class based on the Player Controller class and name it MyPlayerController.
Inside it’s header file, type in the following code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
private: /*Our UI Reference*/ UCollectiblesUI* CollectiblesWidget; protected: /*Property which is pointing to our Widget Blueprint in order to instantiate it using c++*/ UPROPERTY(EditDefaultsOnly) TSubclassOf<UCollectiblesUI> CollectiblesWidgetBP; public: /*Executes when the controller possess a pawn*/ virtual void Possess(APawn* InPawn) override; /*Updates the UI based on the item that the player has collected*/ void UpdateCollectedItems(FText ItemName); |
Then, switch to your source file, and type in the following code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
void AMyPlayerController::Possess(APawn* InPawn) { Super::Possess(InPawn); if (CollectiblesWidgetBP) { //Creating our widget and adding it to our viewport CollectiblesWidget = CreateWidget<UCollectiblesUI>(this, CollectiblesWidgetBP); CollectiblesWidget->AddToViewport(); } } void AMyPlayerController::UpdateCollectedItems(FText ItemName) { ATPBlogProjectCharacter* Char = Cast<ATPBlogProjectCharacter>(GetPawn()); if (Char) { //Updating our UI with the new collected item CollectiblesWidget->AddItemToUI(ItemName); } } |
You may need to modify the UpdateCollectedItems function to fit your needs because I have a reference in my own Character class which might differ from yours. Moreover, don’t forget to include the header file of your character!
Compile and save your code. Switch to your Editor and create a Blueprint based on our Controller Class. Then, make sure to assign the UW_Collectibles to our Collectibles Widget BP as the following image suggests:
We’re done with our controller! Let’s move on, to our character!
Setting up our Character
Open up your Character’s header file, and include the following function:
1 2 |
/*Adds the items to the collectibles UI*/ void AddItemToUI(FText ItemName); |
Then, switch to your Character’s source file, include the “MyPlayerController.h” header file and type in the following implementation of the AddItemToUI function:
1 2 3 4 5 6 |
void ATPBlogProjectCharacter::AddItemToUI(FText ItemName) { AMyPlayerController* Con = Cast<AMyPlayerController>(GetController()); if (Con) Con->UpdateCollectedItems(ItemName); } |
Now that we have all that set up, let’s create our Collectibles!
Creating our Collectibles
Add a new C++ class based on the Actor class and name it ACollectible. Then, inside the header file type in the following properties:
1 2 3 4 5 6 7 8 9 10 11 |
/*Static Mesh component*/ UPROPERTY(VisibleAnywhere) UStaticMeshComponent* SM; /*Just a simple but fancy rotation*/ UPROPERTY(VisibleAnywhere) URotatingMovementComponent* RotatingComp; /*The function that fires when we have an overlap*/ UFUNCTION() void Overlap(AActor* Other); |
Switch to your source file and inside the Constructor instantiate our components:
1 2 3 |
//Creating our components SM = CreateDefaultSubobject<UStaticMeshComponent>(FName("SM")); RotatingComp = CreateDefaultSubobject<URotatingMovementComponent>(FName("RotatingMoveComp")); |
Inside your BeginPlay (and after the Super::BeginPlay()) make sure to register your overlap function:
1 |
OnActorBeginOverlap.AddDynamic(this, &ACollectible::Overlap); |
Then, create the following implementation of the overlap function:
1 2 3 4 5 6 7 8 9 10 11 12 |
void ACollectible::Overlap(AActor* Other) { ATPBlogProjectCharacter* Char = Cast<ATPBlogProjectCharacter>(Other); if (Char) { //Get the name of our item FText Text = FText::FromString(GetName()); //Add the item to our UI Char->AddItemToUI(Text); Destroy(); } } |
Compile and save your code. Then, create a Blueprint based on our collectible class, and assign a static mesh of your liking.
Don’t forget to adjust it’s collision presets like the following image suggests:
We’re almost ready! The last thing we need is to create a GameMode and tell it to “tie” our custom controller with our character!
Setting up a GameMode
Create a Blueprint class based on the default Game Mode that your project already includes:
Just your Blueprint and don’t edit anything! I named my blueprint BP_GameMode.
Then, go to your default map and inside the World Settings, set up the following options:
That’s it! The last thing you need is to place some Collectibles in your Map and test your UI!
A great tutorial, thanks a lot!
Hi Orfeas.
I’ve run into a snag with:
OnActorBeginOverlap .AddDynamic(this, &ACollectible::Overlap);
I’m currently using UE4.19 and this doesn’t appear to work? I think it’s because the Overlap function has too few parameters than what the overlap delegate wants.
Thoughts?
Managed to correct it.
The function should be:
void Overlap(AActor* OverlappedActor, AActor* OtherActor)
And then instead of using ‘Other’ in the function, you would use ‘OtherActor’.