Skip to content
This repository has been archived by the owner on Dec 28, 2021. It is now read-only.
/ kt-ldtk-api Public archive

A Kotlin LDtk API that can be used for any Kotlin Multiplatform or Java projects.

License

Notifications You must be signed in to change notification settings

LeHaine/kt-ldtk-api

Repository files navigation

NO LONGER MAINTAINED

If you need LDtk support consider checking out LittleKt - A Kotlin Multiplatform game framework which has full LDtk loading and rendering support.

Release Version LDtk

About

This is a Kotlin and Java API to parse and load LDtk project files. The ldtk-api module is built for Kotlin Multiplatform which means it works for JVM and JS targets. Other targets have not been tested yet.

This library can be used for any Kotlin Multiplatform or JVM game engine/framework/project. It features a sample LibGDX project for both annotation processing and rendering as well as a KorGE example.

LibGDX Sample Example LibGDX Sample Example

LDtk official website

Helpful links:

Features

  • Annotation processing: An optional annotation that will allow fully generated typesafe code to be used within your game.
  • Compile time code gen: When using the annotation processor, the project code will be generated at compile time and available right away.
  • No runtime reflection: Reflection is used at compile time which is used to generate code.
  • Extremely simple: Parsing and loading a file is extremely easy in just a few lines of code

Versioning

API Version LDtk Version
1.4.0 0.9.3

Usage

Sample code

Create any class and add an @LDtkProject annotation to it with the location to your LDtk file on your projects classpath.

Build your project, and it is ready to be used.

Kotlin example

// designate class for loading and attaching LDtk file to
@LDtkProject(ldtkFileLocation = "sample.ldtk", name = "World")
class _World

fun main(args: Array<String>) {
    // create new LDtk world
    val world = World()
    world.load() // loads the file and parses it

    // get a level
    val level: World.WorldLevel = world.allLevels[0]
    level.load() // force load a level
    // levels are loaded automatically when accessing any layer of that level

    // iterate over a layers tiles
    level.layerBackground.autoTiles.forEach {
        // logic for handling the tile
    }

    level.layerEntities.allMob.forEach { mob ->
        // access entity fields
        val type: World.MobType = mob.type // generated enum class
        val patrolPoint: Point? = mob.patrol // points
        val health: Int = mob.health
    }

    level.layerEntities.allCart.forEach { cart ->
        // field arrays
        cart.items.forEach { item ->
            if (item == World.Items.Pickaxe) {
                // spawn pickaxe
            }
        }
    }
}

Java Example

// designate class for loading and attaching LDtk file to
@LDtkProject(ldtkFileLocation = "sample.ldtk", name = "JavaWorld")
public class SampleJava {
    public static void main(String[] args) {
        // create new LDtk world
        JavaWorld world = new JavaWorld();
        world.load(); // loads the file and parses it

        // get a level
        JavaWorld.JavaWorldLevel level = world.getAllLevels().get(0);
        level.load(); // force load a level
        // levels are loaded automatically when accessing any layer of that level

        // iterate over a layers tiles
        for (LayerAutoLayer.AutoTile tile : level.getLayerBackground().getAutoTiles()) {
            // logic for handling the tile
            int x = tile.getRenderX();
        }

        // iterate over entities
        for (JavaWorld.EntityMob mob : level.getLayerEntities().getAllMob()) {
            JavaWorld.MobType type = mob.type;
            Point patrolPoint = mob.getPatrol();
            int health = mob.getHealth();
        }

        for (JavaWorld.EntityCart cart : level.getLayerEntities().getAllCart()) {
            // field arrays / lists
            List<JavaWorld.Items> items = cart.getItems();

            for (JavaWorld.Items item : items) {
                if (item == JavaWorld.Items.Pickaxe) {
                    // spawn pickaxe
                }
            }
        }
    }
}

Sample code when NOT using the annotation to generate code

val proj = Project("sample.ldtk").apply { load() }
val level = proj.allUntypedLevels[0]
level.load() // this is only needed if levels are saved in separate files!
val gridSize = 16
level.allUntypedEntities?.forEach { entity ->
    val x = entity.cx * gridSize
    val y = entity.cy * gridSize
    entity.json.fieldInstances.forEach {
        if (it.identifier == "Color") {
            val color = it.value!!.content
        }

    }
}
level.allUntypedLayers.forEach { layer ->
    if (layer.type == LayerType.IntGrid) {
        val intGridLayer = layer as LayerIntGrid
        intGridLayer.getInt(0, 5)
    }
}

You can check out a few samples in the samples module.

Download

In your gradle build script ensure you have the kotlin and kapt gradle plugins enabled.

If you are using Kotlin then they may already be enabled.

If you are using Java then they need to be enabled. Warning: This will most likely force you to change any annontationPrcessing dependencies to kapt.

plugins {
    kotlin("jvm") version "1.4.31"
    kotlin("kapt") version "1.4.31"
}

Dependencies for any framework

Note: Check for latest version at the top.

build.gradle.kts

allprojects {
    repositories {
        maven(url="https://jitpack.io")
    }
}
configurations.all { // kapt has an issue with determining the correct KMM library, so we need to help it
    if (name.contains("kapt")) {
        attributes.attribute(
            KotlinPlatformType.attribute,
            KotlinPlatformType.jvm // pass in the JVM 
        )
    }
}

dependencies {
    implementation("com.lehaine.kt-ldtk-api:ldtk-api:$version")
    kapt("com.lehaine.kt-ldtk-api:ldtk-processor:$version")
}