LibGDX is a gaming framework which works on the JVM. Using it, you can create a game for mobile, desktop and web platform.

Kotlin is a language compatible with the JVM (Java Virtual Machine) platform. It’s like Java but shorter.

LibGDX-addons is a set of addons, gradle plugins, …, to ease the development of games using libGDX and Kotlin. Get ride of all boilerplate to dive directly into the code of your game.

Important
This documentation is open source. You can correct it, updated it or add content of you want to. Just Fork it and submit a merge request of your update. Thanks!

Getting started

LibGDX use gradle as a build system. You can use the official setup app to create your game. Instead LibGDX-addons propose a gradle plugin to take care of all gradle setup, for all platform (Currently supported: Desktop and Android) so you don’t have to manage it or update your gradle script.

Setup your game

Create your first game by using IntelliJ. Click in File > New Project

create game 01

Pick Gradle then tick Kotlin DSL build script, choose Kotlin/JVM and go to the next screen by clicking Next.

create game 02

Fill the information asked and click Next until IntelliJ create your project.

Open the file build.gradle.kts and paste this configuration into. It adds necessary repositories for dependencies and add the gradle libgdx plugin.

build.gradle.kts
buildscript {
    dependencies {
        classpath("com.github.dwursteisen.libgdx-addons:libgdx-gradle-plugin:016e8b7")
    }
    // (1)
    repositories {
        mavenCentral()
        google()
        jcenter()
        maven { url = uri("https://oss.sonatype.org/content/repositories/releases/") }
        maven { url = uri("https://oss.sonatype.org/content/repositories/snapshots/") }
        maven { url = uri("https://jitpack.io") }
    }
}

allprojects {
    // (2)
    repositories {
        mavenCentral()
        google()
        jcenter()
        maven { url = uri("https://oss.sonatype.org/content/repositories/releases/") }
        maven { url = uri("https://oss.sonatype.org/content/repositories/snapshots/") }
        maven { url = uri("https://jitpack.io") }
    }
}

apply(plugin = "libgdx")
  1. Add dependency repositories for plugins;

  2. Add dependency repositories for all modules.

Run the command gradlew build: it will download gradle if needed and download all dependencies and create the minimal setup. Once done, it might be long depending of your Internet connection, refresh the project in IntelliJ.

create game 02b
Figure 1. Your project when everything is ready

Run your game

Your game project is now ready!

You can run the game from the command line using ./gradlew run. Gradle will now compile the code that was previously generated and run your game. But it might be more convenient to run the game from IntelliJ.

As you refreshed the project into IntelliJ, a new Run Configuration just appear in your IntelliJ. Click on Add Configuration and check Application run configurations. You will see a run configuration added in IntelliJ to run your game.

create game 03

Draw your first texture

Grab an image and copy it into the src/main/assets directory of the core module. You can find free image / sprite sheet on the OpenGameArt.org.

Run the command ./gradlew build, the command will generate a new class Assets that will contains all of your assets name.

Note
The use of the Assets object is not mandatory. But if your rename one of your assets, it’s practical to have a compilation error instead of your game crashing.

Create your game into the core directory and use it in MainClass.kt.

MyGame.kt
class MyGame : Game() {

    private lateinit var texture: Texture

    private lateinit var batch: SpriteBatch

    override fun create() {
        texture = Texture(Assets.assets_dungeon_sheet_png)
        batch = SpriteBatch()
    }

    override fun render() {
        batch.begin()
        batch.draw(texture, 0f, 0f)
        batch.end()
    }
}
MainClass.kt
object MainClass {
    @JvmStatic
    fun main(args: Array<String>) {
        LwjglApplication(MyGame(), LwjglApplicationConfiguration().apply {
            width = 600
            height = 600
        })
    }
}

If you run your game, the texture will be displayed on the screen.

create game 04

Increase your feedback loop

It’s important to have a quick feedback loop while developing a game. For example, what’s the point of restarting your game when you just updated a texture from your game?

To enable this feature, you need to add a dependency to the libgdx core-addons.

Add this into your build.gradle.kts then refresh the project in your IDE:

build.gradle.kts
project(":core") {
    dependencies {
        implementation("com.github.dwursteisen.libgdx-addons:core-addons:a49ba13")
    }
}

You can now update your game to use the asset manager of libgdx with RefreshableTexture.

MyGame.kt
class MyGame : Game() {

    private val assetManager: AssetManager = AssetManager()

    private lateinit var batch: SpriteBatch

    override fun create() {
        // (1)
        assetManager.setLoader(Texture::class.java, RefreshableTextureLoader(InternalFileHandleResolver()))
        assetManager.load(Assets.assets_dungeon_sheet_png, Texture::class.java)
        // (2)
        assetManager.finishLoading()
        batch = SpriteBatch()
    }

    override fun render() {
        // (3)
        Gdx.gl.glClearColor(0f, 0f, 0f, 1f)
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT)

        // (4)
        val texture: Texture = assetManager[Assets.assets_dungeon_sheet_png]
        batch.begin()
        batch.draw(texture, 0f, 0f)
        batch.end()
    }
}
  1. Replace the default Texture Loader with the RefreshableTexture Loader;

  2. Force to load all assets before rendering the game;

  3. Clear the screen;

  4. Getting the texture from the asset manager.

Run your game and while the game is running, apply a modification on the texture file. As soon as you save the file, the texture will be updated in your game.

create game 05
Note
The asset manager is not mandatory. But by using it, you can use the RefreshableTexture for the desktop version of your game and the default texture loader for your android game without having to change your whole code base.

Setup a entity engine

A game is a lot of different entities who share a lot of common behaviours. For example, the player and an enemy have bot a position. They have both a size too. You can create a class that both will inherit. But it will increase your code complexity. Instead, you can compose your entities of different properties: an entity can be a player with a size and a position. An enemy is an entity with a size, a position, some other capacities.

[Ashley](https://github.com/libgdx/ashley) is one entity engine for libGDX. It is very easy to setup in your project. Add ashley as dependencies of your project then refresh it in your IDE.

build.gradle.kts
project(":core") {
    dependencies {
        implementation("com.github.dwursteisen.libgdx-addons:core-addons:a49ba13")
        implementation("com.badlogicgames.ashley:ashley:1.7.3")
    }
}

The code of your game needs to be updated to add the entity engine and create your first entity.

MyGame.kt
class MyGame : Game() {

    private val assetManager: AssetManager = AssetManager()

    // (1)
    private val engine = Engine()

    private val viewport: Viewport = FitViewport(200f, 200f)

    override fun create() {
        assetManager.setLoader(Texture::class.java, RefreshableTextureLoader(InternalFileHandleResolver()))
        assetManager.load(Assets.assets_dungeon_sheet_png, Texture::class.java)
        assetManager.finishLoading()

        // (2)
        engine.addSystem(RenderSystem(viewport,
            mapOf(SPRITE to SpriteStrategy())
        ))
        engine.addSystem(PlayerSystem())

        // (3)
        val split = TextureSplitter(assetManager).split(
            Assets.assets_dungeon_sheet_png, 16, 16
        )
        val playerSprite = split.get(column = 19, row = 7)

        // (4)
        val player = engine.createEntity().apply {
            add(Player())
            add(Position())
            add(Size(16 v2 16))
            add(Textured(texture = playerSprite))
            add(Render(SPRITE))
        }
        engine.addEntity(player)
    }

    override fun render() {
        Gdx.gl.glClearColor(0f, 0f, 0f, 1f)
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT)

        // (5)
        engine.update(Gdx.graphics.deltaTime)
    }

    override fun resize(width: Int, height: Int) {
        viewport.update(width, height)
    }
}
  1. Create an EntityEngine. Please note that you can use a PooledEntityEngine too;

  2. Add all systems to the engine. For now, we will just add a system that will render all entities on screen;

  3. Split the texture to get only a region. This region will be use to display the player;

  4. Create your first entity. This entity is marked as the Player. Has a position, a size, a texture and marked as to be rendered;

  5. In the render loop, update the engine.

When creating the player, please note that only the component Player needs to be created.

Components.kt
package step4

import com.badlogic.ashley.core.Component
import com.github.dwursteisen.libgdx.ashley.StateComponent

class Player : Component
class Door : StateComponent()
class Switch  : StateComponent()

Other components are provided by ashley-addons: Position, Size, …

Important
Do not forget to set a size! Otherwise your entity will have a width and heigh of 0 so will be invisible.

The player can be moved by detecting if some keys where pressed, like left, right, …

PlayerSystem.kt
class PlayerSystem : IteratingSystem(Family.all(Player::class.java).get()) {

    private val position = get<Position>()

    private val speed = 64f

    override fun processEntity(entity: Entity, deltaTime: Float) {
        if (Gdx.input.isKeyPressed(Input.Keys.LEFT)) {
            entity[position].value.add(-speed * deltaTime, 0f)
        } else if (Gdx.input.isKeyPressed(Input.Keys.RIGHT)) {
            entity[position].value.add(speed * deltaTime, 0f)
        }

        if (Gdx.input.isKeyPressed(Input.Keys.UP)) {
            entity[position].value.add(0f, speed * deltaTime)
        } else if (Gdx.input.isKeyPressed(Input.Keys.DOWN)) {
            entity[position].value.add(0f, -speed * deltaTime)
        }
    }
}

Regarding the key that was pressed, the position of the entity is extracted.

Note
The property component is accessed from the entity like it is a map. More information can be found in the [ashley-addons] section.

Create a state machine

A game can be composed of a lot of state machine. But what is a state machine? It’s an entity that can be in state and regarding a certain event transition can goes in another state.

A simple example could be a door: it can be open and goes in a close state if the player push a switch.

create game 06

React to events

Package your game for Desktop

Tip
WIP

Package your game for Android

Tip
WIP

LibGDX Libraries

Tip
WIP

admob-addons

Tip
TODO

aseprite-addons

Tip
TODO

ashley-addons

Tip
TODO

core-addons

Tip
TODO

libgdx-test

Tip
TODO

LibGDX Gradle plugins

Tip
WIP

Assets Gradle Plugin

When developing a game, you need to manage resources. Time to time you need to rename a file. In such case, you need to track every time you reference the file name by a string.

val sprite = load("mySprite.png")

To avoid to search for every place you’re loading the file using a String, the assets plugin can generate an Assets object that will hold all references to all your assets.

Assets.kt
object Assets {
    val mySprite: String = "mySprite.png"
}

If you rename an asset, then the class will be re-generated and you game will not compile! Which is way better than compile and crash later.

Tip
It’s better to have a game that doesn’t compile than a game that compile, run and crash only when the game will load the missing asset.

Configuration

build.gradle.kts
import com.github.dwursteisen.libgdx.assets.AssetsPlugin
import com.github.dwursteisen.libgdx.assets.AssetsPluginExtension

plugins {
    id("assets")
}
apply<AssetsPlugin>()

configure<AssetsPluginExtension> {
    assetsClass.set(project.buildDir.resolve("generated/NewAssets.kt"))
}

You can configure the plugin using several options:

open class AssetsPluginExtension(project: Project) {
    /**
     * Which directory should be scan so all files will be referenced in the Assets object.
     */
    val assetsDirectory = project.createProperty<FileCollection>()
        .value(project.files("src/main/assets"))

    /**
     * Which class (aka Assets object) will reference all assets name.
     */
    val assetsClass = project.createProperty<File>()
        .value(project.buildDir.resolve("generated/Assets.kt"))
}