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.centerPositionextension method was added to allow quick actor centering, hiding the necessary math.Group.contains(Actor)method was added to supportinoperator. You can check if anActoris a direct child of aGroupwithactor in groupsyntax.GroupandStagesupport actor adding and removal through+=and-=operators.Stage.contains(Actor)method was added to supportinoperator. This will reporttrueif theActoris on theStage(it does not have to be a direct child ofStageroot group).Actor.alphaandStage.alphainlined extension properties were added to support easy modification ofColor.avalue.Actor.setKeyboardFocusand.setScrollFocusallow to quickly (un)focus the actor on its stage.
- Lambda-compatible
Actor.onChangemethod was added. Allows to listen toChangeEvents. - Lambda-compatible
Actor.onClickmethod was added. AttachesClickListeners. - Lambda-compatible
Actor.onTouchDownandActor.onTouchUpmethods were added. AttachesClickListeners. - Lambda-compatible
Actor.onKeymethod was added. Allows to listen toInputEventswithkeyTypedtype. - Lambda-compatible
Actor.onKeyDownandActor.onKeyUpmethods were added. They allow to listen toInputEventswithkeyDownandkeyUptype, consuming key code of the pressed or released key (see LibGDXKeysclass). - Lambda-compatible
Actor.onScrollFocusmethod was added. Allows to listen toFocusEventswithscrolltype. - Lambda-compatible
Actor.onKeyboardFocusmethod was added. Allows to listen toFocusEventswithkeyboardtype. KtxInputListeneris an open class that extendsInputListenerwith no-op default implementations and type improvements (nullability data).onChangeEvent,onClickEvent,onTouchEvent,onKeyEvent,onKeyDownEvent,onKeyUpEvent,onScrollFocusEventandonKeyboardFocusEventActorextension methods were added. They consume the relevantEventinstances as lambda parameters. Both listener factory variants are inlined, but the ones ending with Event provide more lambda parameters and allow to inspect the originalEventinstance that triggered the listener. Regular listener factory methods should be enough for most use cases.
- Global actions can be added and removed from
Stagewith+=and-=operators. - Actions can be added and removed to individual
Actorinstances with+=and-=operators. Action.theninfix 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.alonginfix 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, thethenfunction 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, thealongfunction may be preferred to avoid creating multiple nested ParallelActions.+=operator adds an action to an existingSequenceActionorParallelAction.Action.repeatandAction.repeatForeverallow to repeat a chosen action by wrapping it with aRepeatAction.
txtinlined extension properties added toLabelandTextButtonwidgets. Since types ofgetTextandsetTextmethods in both of this 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 to still hopefully readabletxt.
Centering actor on a stage:
import ktx.actors.*
window.centerPosition()Adding and removing actors with operators:
import ktx.actors.*
table += button
table -= label
stage += tableChecking if actor is on a stage or in a group:
import ktx.actors.*
button in stage
button in tableQuickly accessing actor and stage alpha color value:
import ktx.actors.*
label.alpha = 0.5f
stage.alpha = 0.2fFocusing 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 += parallelChaining 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 += parallelAdding 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
Scene2Dutilities, as well as some extended widgets to address some of the LibGDX API problems. It is written in Java, though. - Kiwi is a general purpose Guava-inspired LibGDX Java utilities
library, which contain some
Scene2Dhelpers. - LibGDX Markup Language makes it easier to build
Scene2Dviews thanks to its HTML-inspired syntax.