Progress Update #24
Even more UI
As it turns out, making a good UI takes time; who would've thought. That is why this week was dedicated entirely to fleshing out the overview UI, and I'm still not done. This process though has been taken up by two main aspects: formatting and functionality.
Formatting
Out of the two, this is the one I have the least experience in. I have some general knowledge about Unreal Motion Graphics (UMG: Unreal's in-editor UI creation tool) and the formatting capabilities it has, but I definitely learned a fair amount this week.
Size Box
The first problem I had to solve was the clipping on the main info scroll box. As you can see in the following picture, some of the numbers get cut off and some flat-out disappear because they are outside the bounds of the main scroll box
The solution I found for this is a component called a size box. This component basically overrides the width and height of its children. So when I put the info section in a size box with a width override of 340 (the width of the scroll box) everything is forced back into view.
Applying a size box to every element that can be added to the info widget ensures that nothing ever goes beyond the bounds of the scroll box and makes sure elements are always accessible to the player.
Combo Box
The second major thing I learned how to use, or more accurately; bent to my will, was the combo box. In UMG the combo box element is like a dropdown menu. You click it like a button and it opens a dialogue with all the available options. What I wanted to use it for though was an 'add noise layer' button for the shape settings. So you would click a button that said add noise layer then it would open up with all of the existing noise layers, and an option to make a new noise layer.
I accomplished this with some custom blueprints. Basically, when the button is clicked (aka when the combo box is opened) all options are erased, the option for NEW is added then we use the asset registry to find all NoiseLayer assets and add their name as an entry in the combo box. Finally the options are refreshed to show all these new options.
Then when the player selects an option, we will either create and add a new noise layer or use a preexisting noise layer asset by string reference (not the way I would prefer but Unreal has forced my hand). Then we rebind delegates on the planet (we'll get more into that in the functionality section) and reset the combo box.
I don't think this is how a combo box is intended to be used, but it works pretty well in this instance.
Spin Box
The final major formatting change I made was adding spin boxes. I did actually know about spin boxes before this, I had just not realized that this would be the perfect place for them.
So before this week, editable numeric values (e.g. a celestial body's mass) were set by an editable text box. This caused a lot of behind the scenes headache having to convert from text to string to number and back again to get and set the variable as well as needing to keep track of the last valid entry.
So when I designed the shape settings I realized that spin boxes would be perfect for this application. I could set a minimum and a maximum, they could handle integer and float values seamlessly, and it gave an easier user experience being able to drag a number slider as opposed to having to type in a number every time.
Functionality
Once I had all the UI in place I needed to make it actually take effect the planet. I already had C++ functions on the planet for OnShapeSettingsUpdated() and OnColorSettingsUpdated(), I just needed to find a way to call them when the respective settings were changed. In the editor I could just use PostEditChangeProperty() but as it's an editor only function I would have to find another way.
Luckily for me, I had just watched an incredible video called Blueprints vs. C++: How They Fit Together and Why You Should Use Both by Alex Forsythe all about how C++ and blue print complement each other in the engine and also about the greater design philosophy of the engine. I would highly recommend that any beginner or intermediate game developer give it a watch, it is definitely worth your time (as are all of the videos on his channel).
The idea that I took away from this video that helped me to solve this problem was that of one way dependencies. Meaning that class A can depend on class B, but class B shouldn't have to know anything about class A to do what it needs to. This was a kind of mind-blowing concept as, up to this point, I would have used a two-way dependency to get around the updated settings problem. In the video he namedrops the solution to this problem: 'delegates'.
Delegates (at least in my use) allow for a class to call a function on another class without knowing what that other class is or even what function it's calling. In unreal this is pretty simple to implement. Firstly, under the generated body macro of the class you want to broadcast the delegate you define the delegate with a macro (a list of all possibilities can be found here). Then you create a variable of the type of that delegate, probably in the public section. Then wherever you want the delegate to broadcast you can use the delegate variable .Broadcast() for multicast and .Execute() for single-cast.
e.g.
ShapeSettings.h
In this case I am using multicast because one ShapeSettings can be referenced by multiple actors |
From there you go to the class where you want the delegate to call a function. Access that delegate variable from before and bind the function you want it to call. I do this on begin play and whenever noise layers are added or removed (like the add noise layer blueprint from before).
e.g.
Planet.cpp
That's really all there is to the functionality I added this week. I still want to be able to edit the color gradients in-game and I have yet to add a widget info section for rings and atmosphere. I'm confident that I can finish both the rings and atmosphere widget within a day, but the gradient editing has me worried. I 100% believe I'll be able to hit the May 31st deadline for the alpha, just that some of the features might not be as perfect as I would like.
Comments
Post a Comment