Hi there. I’ve had a bit of a play around with this one and hopefully I’m understanding what you’re after. From my understanding, you’re after how much a 3D widget can be manipulated? Please correct me if I’m wrong here. Based on that assumption though, this is a basic example of what you can do for a VR user interface for something like an RTS and how it works. Please note that it’s pretty primitive so it won’t look amazing, however it will hopefully show a basic direction of which to go.
- Firstly, i created the user interface (BuildingUI). It has a few basic components, such as buttons and text. The buttons are placed in vertical boxes for alignment and organisation. There is also some text that entails how many resources the player has.
In terms of manipulating UI elements based on boolean functions (E.g. my player has 100 gold and infantry costs 50, thus they should be able to click on the infantry button.), this is where binding comes into play. You can bind different attributes of UI elements. In this example, I’ve bound the “Is Enabled” attribute of each of the buttons to a function. To bind an attribute, you just need to click on the “Bind” dropdown box that appears beside the attribute that you wish to manipulate and then select “Create Binding”. At this point, it will create a function that has a return type of whatever you’re manipulating. (In this case, since I’m changing a boolean (IsEnabled), the return type for the function is a boolean.). Once an attribute is bound, you can manipulate it as you would any other function. In this example, I’ve stored a boolean value for each button. Whenever the value for the appropriate boolean variable is changed, the IsEnabled function will reflect that change. It’s the equivalent of bool IsEnabled() { return isMyButtonEnabled;}
- Once I bound the appropriate attributes to functions, I created some [animations][3]to make the buttons disappear and reappear when they are required. I simply change the alpha from 0 to 1 for the appropriate button and text when the player can afford to purchase what the button corresponds to. I created a function called Update Buttons that would then play the appropriate animation based on whether the player can afford something or not. The below image is how I determine when to play an animation:
- With animation and button manipulation out of the way, I then bound the “On Click” events for the buttons, which call event dispatchers. To bind an event, if you click on a button and scroll down to Events, there will be a number of events that you can bind by clicking the green + button.
.
This allows anything that has bound those events to perform a function when the event is called. For this example, whenever a player clicks on the “Purchase Infantry” button, I perform a call to an event dispatcher named “On Purchase Infantry”.
-
With the UI complete, I then moved onto the player controller. For this example, I’ve stored the resources in the player controller (Not the best place to store them, but easy to access.). The controller has two main functions: Update Gold and Update Minerals (Those are my resources). Whenever these functions are called respectively, they add or subtract a given amount from their respective stockpile and then call an event dispatcher. On the controllers “Begin Play” event, I also created a looping event that increases the amount of gold/minerals the player has by 3.
-
With the controller storing the resources and calling event dispatchers whenever the values of the resources were changed, we now need the building that we’re going to be purchasing things from. I created an actor called BasicStructure and gave it a static mesh component and a widget component. The widget component is how I’m displaying the UI in 3D. I setup the widget component to use the BuildingUI class so that we could see the UI where-ever the building is placed. In this example, the BasicStructure actor is the glue that binds the resources and the user interface.
-
On the “Begin Play” event for BasicStructure, I store three references.
- A Player Pawn reference (This is for rotating the UI towards us)
- The player controller reference (For getting resource information)
- The BuildingUI reference (For telling the UI when to update button visibility and how it displays resources etc.)
Once those references were stored, I updated the BuildingUI based on the resources inside of PlayerController. This allows the UI to be in a state where it knows what to show and what not to show.
The functions shown in that image such as “Can Afford Infantry” are just checking whether the player has enough gold/minerals for a resource. The result is sent up to the UI so it can determine whether to display the corresponding button or not.
Continuing on from where we left off in the “Begin Play” event, I then bound the two event dispatchers that were created in the player controller to an event called “On Resources Gained”. This just updates the UI with the macro in the above image. After those dispatchers were bound, I then bound the dispatchers from the UI (The ones that would activate when the player clicked a button i.e purchase infantry). These events would call the player controller to get it to update gold/minerals.
For a TL;DR version:
- On begin play, we grab the references we need to player controller, ui and pawn.
- We bind the appropriate event dispatchers so we can do something when they’re called.
- When the player clicks on a button to make a purchase, the event dispatcher is called which in turn calls an event in BasicStructure (an event called OnPurchaseInfantry for example), which then updates the gold in the player controller, which then calls its event dispatcher (OnUpdateGoldPerformed), which then calls the event “OnResourcesGained” to update the UI.
As for the player pawn reference, I use that to rotate the widget component towards the player using [Find Look at Rotation][7]. Not terribly relevant for this discussion but I felt the explanation might be incomplete without it.
- I then created a pawn based off of the SpectatorPawn that could float around and allows you click what’s directly in front of it. To click a 3D widget, a pawn requires a [WidgetInteraction component][8].
Hopefully this answers the question and I’m not completely off base. If you would like to look at my example, I’ve [uploaded an example onto Github.][9] If you download the project, you will just need to go into the “CapabilitiesOfWidgetQuestion” folder and open up the map in the “Map” folder.