This is a library which aims to allow easy integration of LDTK (Level Developer's Toolkit) in LibGDX projects. LDTK is an awesome, user friendly 2D tile-editor.
implementation 'com.github.RedSponge:ldtk-gdx:v0.2'
In html dependencies:
implementation "com.github.RedSponge:ldtk-gdx:v0.2:sources"
In GdxDefinitions.gwt.xml
:
<inherits name="com.redsponge.LDTKGdx"/>
LDTK has its own type system, consisting of numbers, strings, positions, and even your own classes and enums. The LDTKTypes
class is in charge of conversions between LDTK types and Java types. You must create and handle an instance of it to load maps.
LDTKTypes types = new LDTKTypes();
To load an ldtk
file (a map), use the LDTKMap
class:
LDTKTypes types = new LDTKTypes();
LDTKMap map = new LDTKMap(types, Gdx.files.internal("my_map.ldtk"));
Once loaded, you can access the different levels by name or uid:
LDTKLevel myLevel = map.getLevel("Level_0");
LDTKLevel myOtherLevel = map.getLevel(123);
Once you have access to an LDTKLevel
instance, you can simply call its render
method with an active SpriteBatch
to draw it. It will be rendered at its specified position in the editor (So to draw an entire map, just loop over the levels and call render
for each one).
// Drawing a specific level:
myLevel.render(batch);
// Drawing a whole map:
for(LDTKLevel level : map.getLevels()) {
level.render(batch);
}
There are 2 essential types of layers in LDTK: entity layers and tile layers. Tile layers are in charge of drawing and entity layers hold extra information.
// Access layers by type:
Array<LDTKEntityLayer> entityLayers = level.getEntityLayers();
Array<LDTKTileLayer> tileLayers = level.getTileLayers();
// Access a layer by its name
LDTKLayer layer = level.getLayerByName("BoundingBoxes");
// Or even more useful - downcast it
LDTKEntityLayer layerButDowncasted = (LDTKEntityLayer) level.getLayerByName("BoundingBoxes");
To access an entity layer's entities and their fields, simply use the getEntitiesOfType
method on the layer to get the enemies, and the get
method on each enemy to get its field contents.
// Getting all entities of type "Enemy"
Array<LDTKEntity> enemies = entityLayer.getEntitiesOfType("Enemy");
// Accessing an enemy's fields
LDTKEntity myEnemy = enemies.get(0);
String enemyType = myEnemy.get("type");
int enemyHealth = myEnemy.get("health");
int enemyX = myEnemy.getX();
int enemyY = myEnemy.getY();
// Printing all of the enemies
for(LDTKEntity enemy : enemies) {
String type = enemy.get("type");
int hp = enemy.get("health");
System.out.println("Oh look! An enemy of type " + type + " with " + hp + " HP at (" + enemy.getX() + ", " + enemy.getY() + ")!");
}
(Thanks to Lyze for making this work with GWT (html)).
Instead of using the generic LDTKEntity
class, you can make your own class for each defined entity, and access the fields that way:
package com.redsponge.ldtktest;
// Example enemy class
public class LoadedEnemy
{
// The position of the enemy in the map (getX(), getY())
@LDTKPositionField
private Vector2 position;
// Other fields
@LDTKField
private String type;
@LDTKField("health")
private int hp;
public Vector2 getPosition() {
return position;
}
// Other getters ...
}
Then, to get an array of the enemies from before, but converted to this new, cool class, just use the getEntitiesConverted
method on the entity layer:
Array<LoadedEnemy> enemies = entityLayer.getEntitiesConverted("Enemy", LoadedEnemy.class);
Important: The conversion is mildly expensive (All objects need to be constructed in the given type), and so the result should be cached.
For each one of the classes which use the annotations, add a line in your GdxDefinitions.gwt.xml
which looks like this:
<extend-configuration-property name="gdx.reflect.include" value="path.to.your.Class" />
i.e.
<extend-configuration-property name="gdx.reflect.include" value="com.redsponge.ldtktest.LoadedEnemy" />
LDTK allows you to create custom enums as entity fields (for example, an EnemyType
enum would be much better than a simple string field). In order to use these enums in your code, you must create matching Java enum classes.
public enum EnemyType {
Zombie,
Skeleton,
Bat
}
Then, register then enum in your LDTKTypes
instance (Yes, the one from before 😄)
// types.addEnum("Type name in LDTK", MatchingClass.class)
types.addEnum("EnemyType", EnemyType.class);
After that, just load your map(s) regularly. The enum will now be the type you receive when calling get
on fields which should return the enum, and it will be recognized properly in annotated (reflection-y) classes.
You might want to get the levels neighbouring a level, for transitions/drawing purposes. To do so, simply use the getNeighbours
method a level, and then use get
with the direction of your choosing:
IntArray neighbours = level.getNeighbours().get(NeighbourDirection.Left);
This will return an IntArray
containing the level ids of the neighbours. (Reminder: map.getLevel(id)
to get a level by its id 😉)
To get all neighbours around a level, regardless of direction, just use NeighbourDirection.All
.