#level #tile #layer #ldtk #tileset #value #json

micro_ldtk

Load data from LDTK, index it and make it accessible through Bevy assets, extract and use autotile rules

12 releases (7 breaking)

0.11.0 Jul 9, 2024
0.10.0 Feb 25, 2024
0.9.1 Jan 20, 2024
0.7.0 Aug 27, 2023
0.3.0 Apr 23, 2023

#44 in Game dev

36 downloads per month

Apache-2.0

610KB
10K SLoC

micro_ldtk

https://crates.io/crates/micro_ldtk https://docs.rs/micro_ldtk

micro_ldtk provides a feature rich layer on top of raw LDTK JSON data, focused on the Bevy engine, and with a goal of forward compatible support for as many LDTK schema versions as is sensible.

Installation

By default, micro_ldtk provides support for the latest LDTK schema version (for a value that also includes N-1, as there may be some time lag between the latest LDTK version being published and a new version of micro_ldtk being published)

To either support a different LDTK schema version, or to pin your version, you will need to disable default features and select the schema version you need:

[dependencies]
micro_ldtk = { version = "0.8.0", default-features = false, features = ["ldtk_1_4_1", "autotile"] }

Features

  • autotile: Provides type conversions from LDTK projects to micro_autotile AutoRuleSet structs. Re-exports micro_autotile as autotile.
  • no_panic: Replaces explicit panic! calls (unwrap, expect, panic, etc) with aborts. This can reduce WASM binary size, but may not cover all areas. PRs welcome.

LDTK Versions

Supported versions of LDTK are enabled by using feature flags. Only one flag should be enabled at a time, otherwise the exported types will conflict. Some versions don't have any schema changes, meaning that some flags will have identical data structures - check the change log for your LDTK version to see if there are any changes. Schema changes are considered to be any change, addition, or removal in the JSON schema that affects any field or property other than metadata, e.g. schema title & schema version

If you only access basic data about a map, there is a strong chance that updating to the latest version will not require any changes to your code. The easiest way to make sure your project will work with a certain LDTK version is to open the ldtk file in the corresponding version of LDTK and save it again.

Feature Flag Uses Schema Version
ldtk_1_5_3 v1.5.3
ldtk_1_4_0, ldtk_1_4_1 v1.4.0
ldtk_1_3_0 v1.3.0
ldtk_1_2_5 v1.2.5
ldtk_1_2_4 v1.2.4
ldtk_1_2_3, ldtk_1_2_2 v1.2.2
ldtk_1_2_1, ldtk_1_2_0 v1.2.0
ldtk_1_1_3, ldtk_1_1_2 v1.1.2
ldtk_1_1_1, ldtk_1_1_0 v1.1.0
ldtk_1_0_0 v1.0.0

Usage

First, include the plugin in your app. This will include an asset loader for LDTK files, and will create resources for indexed levels and tilesets. In the context of this README, "tilesets" refers to the metadata associated with tile IDs, and not the spritesheets or images that might be rendered to represent the tile ID.

Levels and tilesets must have globally unique names, or the last one loaded will be used.

use bevy::prelude::*;
use micro_ldtk::MicroLDTKPlugin;

fn main() {
    App::build()
        .add_plugins(DefaultPlugins)
        .add_plugin(MicroLDTKPlugin)
        .run();
}

Elsewhere, load one or more LDTK projects through the asset server:

use bevy::prelude::*;
use micro_ldtk::Project;

#[derive(Resource, Debug)]
pub struct MyLdtkProject(Handle<Project>);

pub fn startup(
    mut commands: Commands,
    asset_server: Res<AssetServer>,
) {
    let project: Handle<Project> = asset_server.load("path/to/project.ldtk");
    commands.insert_resource(MyLdtkProject(project));
}

When LDTK projects are loaded or modified (when asset events are enabled), the levels and tilesets will be parsed into a more ergonomic format, and stored in resources. These resources can be accessed through the LevelIndex and TilesetIndex resources.

use bevy::prelude::*;
use micro_ldtk::{LevelIndex, TilesetIndex};

pub fn process_some_level(
    level_index: Res<LevelIndex>,
    tileset_index: Res<TilesetIndex>,
) {
    let level = level_index.get("level_name").unwrap();
    let tileset = tileset_index.get("tileset_name").unwrap();

    for layer in level.layers() {
        layer.for_each_tile(|x, y, tile_data| {
            let tile_metadata = tileset.get(tile_data.gid());
            log::info!("Got tile {:?} at [{}, {}]", tile_metadata, x, y);
        });
    }
}

Dependencies

~43–80MB
~1.5M SLoC