Posted October 19, 2024 by AbyssEclipse
#C++ #Unreal Engine 5 #Jigsaw Puzzle #Puzzle
At first, I tried to write the C++ version of what the guy was doing with the blueprints using my existing knowledge and by reading the source files and documentation. However, I wasn’t even able to get the constructor working and start adding Images to my Widget.
The constructor for UUserWidgets is much different from what I’m used to, so I didn’t know how to use it.
Typical C++ constructor:
UUserWidget Constructor (That I found in the source code):
This is the closest I was able to get:
However, this didn’t work as desired, so I decided to do more research.
I searched for a youtube video about using UUserWidget with C++. I found this video:
UMG Widgets with C++ in Unreal Engine 5
From this video, I learned that there are three ways of creating UI in UE5 with C++:
What I found interesting about this tutorial is that it seems that in this tutorial, the man doesn’t use constructors at all. What he does instead is declare the variables “HealthBar” and “PowerBar”, and then uses the macro “meta = (BindWidget)” make it so that you not only can, but need to override these variables in the derived blueprints.
His cpp file contains no constructor, and only functions that affect the functionality of the widget.
This is very different from the approach I learned during the summer, where you would create default subobjects in C++ and attach them to the root component or whatever other component you want in the constructor.
Ben UI is an amazing website that covers how to make professional UI in Unreal Engine. I read some interesting articles on it:
Introduction to C++ UIs in Unreal
Connect C++ to UMG Blueprints with BindWidget
Important info about the difference between Slate and UMG:
UImage
is the UMG class, and it contains a SImage
instance inside it.Why would we want to use BindWidget
and C++ instead of just writing all our logic in Blueprints? (Info taken from BenUI website):
Pros:
Cons:
(Info taken from BenUI website):
Though I'd learned some interesting information from BenUI, and I found out that I technically didn't need a constructor for my purposes, the lack of information about why normal C++ constructors don't work with UMG classes. Hence, I did a bunch of forum scrolling. Here are the useful forums I found:
Difference between NativeConstruct method and class constructor
Here is the answer I was looking for
It seems that the reason you can't call normal constructors on UMG classes is because they are wrappers for Slate class- so you need to use a special format for them (namely, in the form of using UE5's NativeConstruct function). However, I was still interested in why Slate was a "native class" unlike UObjects, and what a "native class" even is, so I decided to do yet more research.
I found this interesting page that had some Unreal Engine Documentation:
Native classes are classes that are, unsurprisingly, native to the engine- they contain C++ implementation in the source code.
That is all well and good, of course, but I still don't understand how that applies to UObjects and Slate and UMG. However, I feel I've already gone above and beyond what I needed to learn for this simple task of creating a constructor for my Puzzle Widget class, so I think it's best I stop here.
Here is the progress I had made after implementing all this research into my code:
One problem I had is that my WBP didn’t look the same as the guy’s in the video. His changed colour to the ‘dynamic material’, but mine stayed white. I had a theory that the reason why it didn’t is because the dynamic material instance is created dynamically at runtime, so maybe it would run during the game but not in editor. I didn’t understand why his worked but mine didn’t. Usually, I dislike moving on to next steps while I still have unresolved issues, since the more code you have, the harder it is to realize where exactly the issue lies. As such, I spent several days trying to find what the problem was, but no matter what I did, I couldn’t find any solution. I also couldn’t test the widget at runtime because I wasn’t at that place in the tutorial yet. In the end, I decided to just move on.
Here's the code I had at the end: