Capabilities of widgets, how should I do this?

So what I’m setting out to create is an RTS game in VR. What I would like to have is an interface that pops up above a structure. The interface will rotate to follow the camera. The buttons displayed will be dynamic, they will change and be enabled/disabled based on things like, enough resources to create a unit or buy an upgrade, different buttons becoming available once certain progress is made, etc.

So far this is how I’ve done this
BPs:
BaseStructure - Parent class for structures, contains logic shared for all buildings. Health, percentComplete when building, etc.
Structure_*** Class for each type of structure with the appropriate mesh, and UIActor. Chid of BaseStructure

BaseUIActor - Parent class for actor the widget component is added to. No logic yet but seemed like I should have a parent class here
UIActor_*** Class for each actor with a widget component attached.

UIWidget - User Widgets with the graphics for the UI, buttons, etc

Where I’m struggling now

I can’t quite figure out how dynamic a widget can be. Simplest case, say I have two buttons, but one button should not be visible until a certain criteria is met. What I’ve been trying to do is use a simple boolean in the UIActor BP, as use that boolen to determine whether a button should be visible or not, but I can’t figure it out. Even if I have to make a custom event within the widget and call that, I can’t figure out how to manipulate buttons.

I’m wondering if what I’m trying to do might be more appropriately done by making a widget for every possibly button that will exist, then create a mesh for the UI that will pop up and add a widget component for each button?

That seems like more work, and a nightmare with toggling visibility for the UI mesh and the widgets,but I just can’t find appropriate documentation on how to change widget properties to do what I want

Any suggestions on an easier way I should be doing this?

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.

  1. 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;}

  1. 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:

  1. 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”.

  1. 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.

  2. 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.

  3. 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.

  1. 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.