Extensions and utilities for stages, actors, actions and event listeners.
Scene2D
API is not that easy to extend in the first place - due to hidden fields and methods, sometimes copy-pasting
a widget class and modifying the relevant lines is the only way to implement an actor "extension". Most event listeners
cannot be used with Kotlin's pleasant lambda syntax. Actions API is pretty powerful, but can be nearly unreadable when
it comes to chaining.
- Null-safe
Actor.isShown()
method was added to make it possible to check if actor is currently on aStage
. Actor.centerPosition
extension method was added to allow quick actor centering, hiding the necessary math.Group.contains(Actor)
method was added to supportin
operator. You can check if anActor
is a direct child of aGroup
withactor in group
syntax.Group
andStage
support actor adding and removal through+=
and-=
operators.Stage.contains(Actor)
method was added to supportin
operator. This will reporttrue
if theActor
is on theStage
(it does not have to be a direct child ofStage
root group).Actor.alpha
andStage.alpha
inlined extension properties were added to support easy modification ofColor.a
value.Actor.setKeyboardFocus
and.setScrollFocus
allow to quickly (un)focus the actor on its stage.
- Lambda-compatible
Actor.onChange
method was added. Allows listening toChangeEvents
. - Lambda-compatible
Actor.onClick
method was added. AttachesClickListeners
. - Lambda-compatible
Actor.onTouchDown
andActor.onTouchUp
methods were added. AttachesClickListeners
. - Lambda-compatible
Actor.onKey
method was added. Allows listening toInputEvents
withkeyTyped
type. - Lambda-compatible
Actor.onKeyDown
andActor.onKeyUp
methods were added. They allow listening toInputEvents
withkeyDown
andkeyUp
type, consuming key code of the pressed or released key (see libGDXKeys
class). - Lambda-compatible
Actor.onScrollFocus
method was added. Allows listening toFocusEvents
withscroll
type. - Lambda-compatible
Actor.onKeyboardFocus
method was added. Allows listening toFocusEvents
withkeyboard
type. KtxInputListener
is an open class that extendsInputListener
with no-op default implementations and type improvements (nullability data).- Lambda-compatible
Actor.onExit
andActor.onEnter
methods were added. They attach listeners invoked whenever the cursor enters or exits the actor respectively. onChangeEvent
,onClickEvent
,onTouchEvent
,onEnterEvent
,onExitEvent
,onKeyEvent
,onKeyDownEvent
,onKeyUpEvent
,onScrollFocusEvent
andonKeyboardFocusEvent
Actor
extension methods were added. They consume the originalEvent
instances as well as some optionally some additional event data as lambda parameters. These listener factory methods ending with Event provide more information about the user input, and allow inspecting the originalEvent
instance that triggered the listener.- Lambda-compatible
Tree.onSelectionChange
method was added. Attaches a listener invoked each time aTree
's node selection is modified.
- Global actions can be added and removed from
Stage
with+=
and-=
operators. - Actions can be added and removed to individual
Actor
instances with+=
and-=
operators. Action.then
infix extension function allows easy creation of action sequences with pleasant syntax. Either wraps the two actions in aSequenceAction
, or if the left action is already aSequenceAction
, adds the right action to it so long chains result in a singleSequenceAction
.Action.along
infix extension function allows easy creation of parallel actions with pleasant syntax. Either wraps the two actions in aParallelAction
, or if the left action is already aParallelAction
, adds the right action to it so long chains result in a singleParallelAction
.+
operator can be used to create action sequences (alternative tothen
). The operator is non-mutating, so it wraps the two actions every time. For long chains, thethen
function may be preferred to avoid creating multiple nestedSequenceActions
./
operator can be used combine actions in parallel (alternative toalong
). The operator is non-mutating, so it wraps the two actions every time. For long chains, thealong
function may be preferred to avoid creating multiple nested ParallelActions.+=
operator adds an action to an existingSequenceAction
orParallelAction
.Action.repeat
andAction.repeatForever
allow to repeat a chosen action by wrapping it with aRepeatAction
.
txt
inlined extension properties added toLabel
andTextButton
widgets. Since types ofgetText
andsetText
methods in both of these widgets are not compatible (get
returnsStringBuilder
,set
consumes aCharSequence
), an extension was necessary to let these widgets fully benefit from idiomatic Kotlin properties syntax. Since Kotlin properties cannot overshadow Java methods, property was renamed totxt
.
Centering actor on a stage:
import ktx.actors.*
window.centerPosition()
Adding and removing actors with operators:
import ktx.actors.*
table += button
table -= label
stage += table
Checking if actor is on a stage or in a group:
import ktx.actors.*
button in stage
button in table
Quickly accessing actor and stage alpha color value:
import ktx.actors.*
label.alpha = 0.5f
stage.alpha = 0.2f
Focusing events on actors:
import ktx.actors.*
textField.setKeyboardFocus(true)
scrollPane.setScrollFocus(false)
Adding a ChangeListener
to an Actor
:
import com.badlogic.gdx.scenes.scene2d.ui.Button
import ktx.actors.*
fun attachListener(button: Button) {
button.onChange {
println("Button changed!")
}
button.onChangeEvent { changeEvent ->
// If you need access to the original ChangeEvent, use this expanded method variant.
println("$this actor changed by $changeEvent!")
}
}
Adding a ClickListener
to an Actor
:
import com.badlogic.gdx.scenes.scene2d.ui.Label
import ktx.actors.*
fun attachClickListener(label: Label) {
label.onClick {
println("Label clicked!")
}
label.onClickEvent { inputEvent ->
// If you need access to the original InputEvent, use this expanded method variant.
println("$this actor clicked with $inputEvent!")
}
label.onClickEvent { inputEvent, x, y ->
// If you need access to the local actor click coordinates, use this expanded method variant.
println("$this actor clicked with $inputEvent at ($x, $y)!")
}
}
Adding an event listener for touch events to an Actor
:
import com.badlogic.gdx.scenes.scene2d.ui.Button
import ktx.actors.*
fun attachTouchListeners(button: Button) {
button.onTouchDown {
println("Button down!")
}
button.onTouchUp {
println("Button up!")
}
button.onTouchEvent(
// If you want to define a single shared listener or need access to the original InputEvent,
// use this expanded method variant:
onDown = { inputEvent -> println("$this actor touched with $inputEvent!") },
onUp = { inputEvent -> println("$this actor released with $inputEvent!") }
)
// ...or with a single lambda.
// In this case you can use InputEvent.Type to distinguish between touchDown and touchUp events:
button.onTouchEvent { inputEvent -> println("$this actor ${inputEvent.type} with $inputEvent!") }
// There are also additional variants with local touch coordinates and mouse/cursor data.
// See the documentation or sources for more details.
}
Adding an EventListener
which consumes typed characters:
import com.badlogic.gdx.scenes.scene2d.ui.TextField
import ktx.actors.*
fun attachKeyListener(textField: TextField) {
textField.onKey { key ->
println("Typed $key char to text field!")
}
textField.onKeyEvent { inputEvent, key ->
// If you need access to the original InputEvent, use this expanded method variant.
println("Typed $key char to $this actor with $inputEvent!")
}
}
Adding EventListeners
which listen to FocusEvent
instances:
import com.badlogic.gdx.scenes.scene2d.ui.ScrollPane
import com.badlogic.gdx.scenes.scene2d.ui.TextField
import ktx.actors.*
fun attachScrollFocusListener(scrollPane: ScrollPane) {
// FocusEvent with scroll type:
scrollPane.onScrollFocus { focused ->
println("Scroll pane is focused: $focused!")
}
scrollPane.onScrollFocusEvent { focusEvent ->
// If you need access to the original FocusEvent, use this expanded method variant.
println("$this actor is focused: ${focusEvent.isFocused}!")
}
}
fun attachKeyboardFocusListener(textField: TextField) {
// FocusEvent with keyboard type:
textField.onKeyboardFocus { focused ->
println("Text field is focused: $focused!")
}
textField.onKeyboardFocusEvent { focusEvent ->
// If you need access to the original FocusEvent, use this expanded method variant.
println("$this actor is focused: ${focusEvent.isFocused}!")
}
}
Chaining actions with infix then
function (SequenceAction
utility) and infix along
function
(ParallelAction
utility):
import ktx.actors.*
import com.badlogic.gdx.scenes.scene2d.actions.Actions.*
val sequence = alpha(0f) then fadeIn(1f) then delay(1f) then fadeOut(1f)
actor += sequence // Adding action to the actor.
val parallel = fadeTo(0f) along scaleTo(0f, 0f) along moveTo(0f, 0f)
actor += parallel
Chaining actions with +
operator (SequenceAction
utility) and /
operator (ParallelAction
utility):
import ktx.actors.*
import com.badlogic.gdx.scenes.scene2d.actions.Actions.*
val sequence = alpha(0f) + fadeIn(1f) + delay(1f) + fadeOut(1f)
actor += sequence // Adding action to the actor.
val parallel = fadeTo(0f) / scaleTo(0f, 0f) / moveTo(0f, 0f)
actor += parallel
Adding and removing actions to stages and actors with operators:
import ktx.actors.*
button += action
button -= otherAction
// Adding global Stage action:
stage += someAction
// Since the action is added to Stage's root actor, it affects all widgets on the Stage.
Accessing and changing text of Label
and TextButton
widgets:
import ktx.actors.*
import com.badlogic.gdx.scenes.scene2d.ui.Label
import com.badlogic.gdx.scenes.scene2d.ui.TextButton
val label = Label("text", skin)
label.txt // Returns "text".
label.txt = "new" // Changes current Label text to "new".
val button = TextButton("Click me!", skin)
button.txt // Returns "Click me!".
button.txt = "Drag me!" // Changes TextButton text to "Drag me!".
Extending KtxInputListener
:
import ktx.actors.KtxInputListener
class MyInputListener : KtxInputListener() {
// Implement the methods that handle events you plan to listen to:
override fun touchDown(event: InputEvent, x: Float, y: Float, pointer: Int, button: Int): Boolean {
// Do something on mouse click.
return true
}
}
- VisUI includes some
Scene2D
utilities, as well as some extended widgets to address some libGDX API problems. It is written in Java, though. - Kiwi is a general purpose Guava-inspired libGDX Java utilities
library, which contain some
Scene2D
helpers. - LML makes it easier to build
Scene2D
views thanks to its HTML-inspired syntax.