0
\$\begingroup\$

I am trying to implement keyboard movement in game main menu which is libGDX Stage with UI-Actors. I'm also trying to code this feature myself since I can't neither find anything relevant to it in the docs nor find libraries for the feature.

I have a bunch of Buttons in the VerticalGroup. Using keyboard UP and DOWN keys, I want to somehow focus, highlight or hover buttons like the way that mouse hovering do. Hovewer, firing FocusEvent on children of the VerticalGroup do not change Button appearance.

So how do I focus these buttons or any other UI element (because there are other menus with more complex UI architecture) ?

Here is the code for the menu (Kotlin, using ktx-scene2d builders and ktx-actors event methods):

class MainMenuUi: Stage() {
    val root = verticalGroup {
        center()
        setFillParent(true)
        expand(true)
        space(spacing)
        fill(0.5f)
        wrap(false)

        textButton("Start")
        textButton("Settings")
        textButton("Exit")

        onKeyUp { key ->
            when(key) {
                Input.Keys.UP -> { /* ??? */ }
                Input.Keys.DOWN -> { /* ??? */ }
            }
        }
    }.also {
        addActor(it)
        keyboardFocus = it
    }
}
\$\endgroup\$
0
\$\begingroup\$

I looked up in the library source code how do Scene2d Actors understand that they are hovered, and it seems to work this way:

  • Button: calling internal ClickListener.isOver(), which, in fact, checking over or pressed private members. Member over is setted when there is an InputEvent with enter type (over is true) or exit type (over is false) and pointer == -1;

  • SelectBox: exact same way that Button does. Except SelectBox itself doesn't have isOver method.

  • Slider: implementing hovering itself, using private mouseOver member; It is adding to itself InputListener that's observe InputEvent hovering the same way that ClickListener does, but change the mouseOver member instead of over.

Other UI elements either inherit from the Button (e.g. CheckBox), or don't have any hovering detection ability (and so they can't change the appearance when they are hovered).

Knowing that, I can implement HoverEvent that can trigger hovering in that limited list of UI elements:

class HoverEvent: InputEvent() {
    init {
        type = Type.enter
        pointer = -1
    }
}

It is change the appearance of the elements, however to un-hover such element I must manually move mouse to it and then outside of it. Or write some UnhoverEvent. This approach, though it seems to me the most correct one, in the end turns out to be inconvenient and in some way impractical.


So, as a workaround, I wrote extension function to the Actor that move cursor position to Actor's center:

fun Actor.moveCursorToIt() {
    val stageCoords = localToStageCoordinates(Vector2())
    val screenCoords = stage.stageToScreenCoordinates(stageCoords)
    Gdx.input.setCursorPosition(
            (screenCoords.x + width / 2).toInt(),
            (screenCoords.y - height / 2).toInt()
    )
}
| improve this answer | |
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.