UMG - Gamepad scrolling menu

Has anyone done something similar to this in UMG?

I want to support both mouse/keyboard and gamepad input for the menu.
So I would have a scroll box of some sorts that is always scrollable (regardless of mouse position) via the middle mouse button or the left gamepad stick.

To accomplish this would I need to bind to an axis in PlayerController?

I then would like to modify the values of each setting by moving the gamepad stick left/right or left/right keyboard keys or clicking the left/right buttons on the screen with the mouse.

I know this can be done in Slate, but I’m wondering if anyone has done it in UMG?

I wouldn’t bind it to a controller because then you can only see a given part of the scrollbox with the extreme of your thumbstick and scrolling on the mouse wheel wouldn’t work.

I’d just check to see if the menu is active and if so then listen for thumbstick input and if the thumbstick moves, send an interface message to your Widget blueprint with the thumbstick value and add to the scrollbox’s scroll level with it.

Where would you listen for the thumbstick input? In the PlayerController?

Sure, there or on the pawn make the most sense, though you could listen on any blueprint as long as “Block Input” is off and a Player number is assigned to it in the class settings.

What do you mean by “you can only see a given part of the scrollbox with the extreme of your thumbstick”?

I’ll look into sending interfaces. I would like for it to scroll one item at a time (like in the video) instead of showing partial widgets on screen as it scrolls.

There’s a bunch of ways you can do this, but here’s a quick and dirty explanation of how I’m doing this right now (Don’t try to follow these images to the letter, they’re not intended to be a true tutorial):

You start with an input event - You can do this by listening for them in your player controller, pawn, or even hack it using the event tick method in the widget itself. In the screenshot below, I’ve bound a custom event inside the widget BP to an event dispatcher inside my player pawn BP, where the actual input events happen. You can then use various logic checks to ensure that the event only fires in the proper context (for example, only when you have the menu open).

Finally, you’ll need an index integer. This integer will be used to tell you which child of your scroll menu is currently active. The basic idea here is that every time you press a button (in this case, up or down on the D-Pad), you will increment or decrement the index variable, and change the context of your scroll menu accordingly.

So you hit up or down on the D-Pad, and when you do, you need to increment or decrement your index variable. Each time the player presses the button, you should also give them some feedback, like a little audio click or whatever. When you’re done with that, you’ll need to change the context of the scroll widget.

In my case, I simply change the scale of the button (this is so the currently active button is slightly larger than the others in your scroll list, easier for the player to see) and then scroll that child into view. (This is so that, in case you have more child widgets than you have visible space in your scroll list, you’ll still be able to view them all). Make sure you check the “Animate Scroll” boolean to ensure it looks all fancy. Finally, you can do whatever else you need to do now that the proper button is active (In my case, you can see I’m setting up descriptions of the item you’ve selected).

Now that you’re able to scroll through your widget, you can simply use the context of another button to take action on the children of your scroll list. For example, if you know that the “Quit Game” function in your scroll list is at index 4, you can code the ‘A’ button in such a way that it will only quit the game when you hit the ‘A’ button while the index is at 4.

This gets somewhat more complicated if you have a dynamic scroll list that could populate different quantitites of children at different times, or a scroll list where the children are not always in the same order. I’m not going to go into much detail about that here, but suffice to say that if you have a dynamic list that can change the number of children, you’ll need to add those children to an array and use it’s length to determine how far you can increment you index, as shown below:

As for a scroll list where your widgets aren’t always in the same order… you’ll basically need to ensure that your child widgets have some sort of unique identifier. I use enums for this. You can see an example of such earlier in this post, at screenshot #3. (Get the child of FoundGearListRows that is at the current index, and then check it’s “Name” enum before setting it’s Gear Description).

Hope that’s helpful!

This looks awesome ! I really appreciate it. I’m going to try and implement this and see if I run into any issues :slight_smile:

@anonymous_user_9259ac75 Okay, so I made some progress on this.
A couple questions.

  1. How do you set the scale for the widgets back to 1,1 when they aren’t the current selection? Do you loop over all of them to do that?
  2. I want to do this for joystick instead of dpad. So I did a BindAxis against the gamepad’s left joystick y axis. This works a little differently than key presses. The bound function is called every frame. So if the player isn’t touching it then it still get the function called. So I am testing against the thumbstick value. If it is > 0 then we are moving up, if < 0 then we are moving down. However, this means I’m calling my Scroll Widget Into View logic a lot and it looks really fast because of that. I could check against previous values to only call once and a while. I wasn’t sure if there was an easier way.

glad you made some progress!

Yes, you’re correct, setting the child widget’s scale back to 1,1 when it isnt active is as simple as using a for each loop to go through each child and individually set them all back to 1,1. Next, you set your active widget back to 1.2,1.2. This will happen fast enough that the player doesnt notice the scale reset during movement.

For #2, the joysticks still have InputAction events just like any other button, and dont necessarily require that you use an input axis. In this case, I would use the input action so that you get a simple 1 or 0 when you press the stick, instead of a variable float value.

For #2, isn’t BindAction for button presses? I wouldn’t be able to see which direction we are moving that way (up/down), correct?
With BindAxis I can slow it down with a Delay but it feels very hacky.

It is, and the gamepad’s joystick has inputs for this process; the joysticks and the triggers serve dual purpose input, as both an axis and an action. (See: Gamepad Left Thumbstick Up, Gamepad Right Thumbstick Down, etc. in the input dropdown lists). Using it as an axis will return a float, 0 to 1, based on the axis position of the joystick. Using it as an action will work as any other button; pressing the joystick in that direction returns an immediate value of 1 no matter the position, and while idling it will be 0.

You’re still going to want to use the axis values of the joysticks for your player’s movement in the world. But in the context of your menu, it makes sense to use the action events.

Depending on how you’re capturing input, you may benefit from putting some Do Once nodes in there somewhere, forcing you to go one step at a time.

Thanks again! I didn’t see Gamepad Left Thumbstick Up/Down before :slight_smile:

I guess that doesn’t really save me much though because then I have to implement logic to support holding the thumbstick down and continuing to scroll.