#ldtk #level #bevy #assets #world #bevy-plugin #projects

bevy_ldtk_asset

A Bevy plugin to support LDtk files as assets!

3 unstable releases

new 0.6.0 Dec 1, 2024
0.5.1 Nov 19, 2024
0.5.0 Nov 18, 2024
0.2.0 Jan 8, 2024
0.1.0 Jan 5, 2024

#122 in Game dev

Download history 1/week @ 2024-09-21 1/week @ 2024-10-12 2/week @ 2024-11-02 295/week @ 2024-11-16 35/week @ 2024-11-23 139/week @ 2024-11-30

471 downloads per month

MIT/Apache

185KB
3.5K SLoC

Bevy LDtk Asset

License docs.rs Crates.io Version CI

A plugin for the Bevy Engine for loading projects from the LDtk level editor.

Description

This plugin aims to provide an asset through Bevy's asset loader system, providing access to the data in an LDtk project.

Philosophy

This crate attempts to provide the user with data that can readily be introduced into Bevy, but does not attempt to offer opinions on how this data should be used. No components, systems (except for debug output), events, resources, etc are provided.

Conventions

When possible, we will convert items to a Bevy compatible format.

  • Fields describing a color will be stored as a bevy color
  • If the field describes a location in space, we will use an I64Vec2
    • NOTE: LDtk, and by extension, this library, uses the convention that the y-axis is positive down. Implementers will need to take care to invert the y-axis when creating components in Bevy's screen space, such as the translation vector in a Transform Component.
    • NOTE: This behavior changed in v0.6.0 .
  • If the field describes a location within an image, we will use a I64Vec2
  • Images will be stored as a Handle<Image>
  • Numeric fields which aren't coerced into a Bevy type are stored in an appropriate 64 bit field (u64, i64, f64)
    • We use 64 bit fields to match the precision provided by LDtk, even though Bevy typically uses 32 bit floats, for example.
  • Iid's are parsed into our local Iid type. It is considered undefined behavior if these are not unique.
  • Uid's are represented by the Uid type, which is of type i64. These are being phased out of LDtk, and may be removed here as well in the future. See here.
  • LDtk pivot fields are converted to and stored as Bevy Anchor fields

Assets

An LDtk project is loaded using Bevy's asset system, and can be added as a Handle<Project> to an ECS entity using the asset server:

#[Derive(Component)]
struct MyComponent {
    project_handle: Handle<bevy_ldtk_asset::project::Project>,
}

fn example_system(mut commands: Commands, asset_server: Res<AssetServer>) {
    commands.spawn(MyComponent {
        project_handle: asset_server.load("some_project.ldtk");
    })
}

Asset labeling

An LDtk project is based on a hierarchical structure where a world (or worlds) contains levels, levels contain layers, and layers can either contain tiles or entities.

These objects are loaded as labeled sub assets of the main project, with their identifiers acting as their labels. LDtk entities will also have their Iid appended after a '@' character.

For instance, an LDtk project with a layout like:

flowchart LR
  Overworld
  Level1
  Ground1[Ground]
  Entities1[Entities]
  Trees1[Trees]
  Level2
  Ground2[Ground]
  Entities2[Entities]
  Trees2[Trees]

  Overworld --> Level1
  Overworld --> Level2

  Level1 --> Ground1
  Level1 --> Entities1
  Level1 --> Trees1
  Entities1 --> Player
  Entities1 --> NPC1
  Entities1 --> NPC2

  Level2 --> Ground2
  Level2 --> Entities2
  Level2 --> Trees2
  Entities2 --> NPC3
  Entities2 --> NPC4
  
  Underworld
  Dungeon1
  Ground3[Ground]
  Entities3[Entities]
  Trees3[Trees]
  Dungeon2
  Ground4[Ground]
  Entities4[Entities]
  Trees4[Trees]

  Underworld --> Dungeon1
  Underworld --> Dungeon2

  Dungeon1 --> Ground3
  Dungeon1 --> Entities3
  Dungeon1 --> Trees3
  Entities3 --> Goblin
  Entities3 --> TrapDoor
  
  Dungeon2 --> Ground4
  Dungeon2 --> Entities4
  Dungeon2 --> Trees4
  Entities4 --> ShadyShopKeeper
  Entities4 --> DubiousPotion

Would result in the following assets and sub-assets being generated:

example.ldtk
example.ldtk#worlds:Overworld
example.ldtk#worlds:Overworld/Level1
example.ldtk#worlds:Overworld/Level1/Ground
example.ldtk#worlds:Overworld/Level1/Entities
example.ldtk#worlds:Overworld/Level1/Entities/Player@e594faf8-fe91-4a25-8082-95ff47040f43
example.ldtk#worlds:Overworld/Level1/Entities/NPC1@d4465592-92ba-4fd7-80c2-7a315d4368be
example.ldtk#worlds:Overworld/Level1/Entities/NPC2@355ad2ee-fbbb-4d30-b5b9-4711ea699121
example.ldtk#worlds:Overworld/Level1/Trees
example.ldtk#worlds:Overworld/Level2
example.ldtk#worlds:Overworld/Level2/Ground
example.ldtk#worlds:Overworld/Level2/Entities
example.ldtk#worlds:Overworld/Level2/Entities/NPC3@8ff0db7d-2969-459a-8f54-467f67aa669f
example.ldtk#worlds:Overworld/Level2/Entities/NPC4@492dceab-8884-4188-90aa-61662444f501
example.ldtk#worlds:Overworld/Level2/Trees
example.ldtk#worlds:Underworld
example.ldtk#worlds:Underworld/Dungeon1
example.ldtk#worlds:Underworld/Dungeon1/Ground
example.ldtk#worlds:Underworld/Dungeon1/Entities
example.ldtk#worlds:Underworld/Dungeon1/Entities/Goblin@c528ae1d-4625-4999-a184-d061253d0595
example.ldtk#worlds:Underworld/Dungeon1/Entities/TrapDoor@2a91e6b2-d63b-4d90-9e5a-f860eea82afd
example.ldtk#worlds:Underworld/Dungeon1/Trees
example.ldtk#worlds:Underworld/Dungeon2
example.ldtk#worlds:Underworld/Dungeon2/Ground
example.ldtk#worlds:Underworld/Dungeon2/Entities
example.ldtk#worlds:Underworld/Dungeon2/Entities/ShadyShopKeeper@55ae7dac-3158-41d1-a8c0-8b586ad19f4c
example.ldtk#worlds:Underworld/Dungeon2/Entities/DubiousPotion@14500cf9-0bd3-440e-b7d0-085a64e79493
example.ldtk#worlds:Underworld/Dungeon2/Trees
example.ldtk#tileset_definitions:GroundTilemap
example.ldtk#tileset_definitions:PlayerTilemap
example.ldtk#tileset_definitions:NpcTilemap
example.ldtk#tileset_definitions:DubiousPotionIcon
example.ldtk#entity_definitions:Player
example.ldtk#entity_definitions:NPC1
example.ldtk#entity_definitions:NPC2
example.ldtk#entity_definitions:NPC3
example.ldtk#entity_definitions:NPC4
example.ldtk#entity_definitions:Goblin
example.ldtk#entity_definitions:TrapDoor
example.ldtk#entity_definitions:ShadyShopKeeper
example.ldtk#entity_definitions:DubiousPotion
example.ldtk#layer_definitions:Ground
example.ldtk#layer_definitions:Entities
example.ldtk#layer_definitions:Trees

See [asset_labels] for a full description.

LDtk dependencies (Images, etc)

An LDtk project will itself point to other assets, such as image files used for tile maps. For these to also work in Bevy, these assets should be in the same asset storage as the .ldtk file. Typically this will be the Rust crate's assets folder. This crate will attempt to reconcile the locations of these assets by assuming the paths in the .ldtk file are relative to the file itself, and that those paths also exist within the same asset storage location as the .ldtk file.

In general, though, if you put both your tile maps, and the LDtk project, in the Bevy project assets/ folder, then Bevy will have no problem finding them.

External Levels

An LDtk project can enable the option to save levels into separate files, with extension .ldtkl. See External Levels.

This is fully supported by this plugin, however the external level files cannot be loaded directly. The entire project file must be loaded, though a user can simply refer to the level's asset path directly. Keep in mind that the entire project file is parsed, even if only a single level label is specified.

Unfortunately there is metadata in the main project which is needed to properly describe a level, and all of it's sub assets. So, loading the entire project is the only option.

See Asset Labeling.

Multi World Projects

LDtk is currently experimenting with a Multi World project. The current default is for an LDtk project to describe a single world, though the option is available to select the multi world behavior in the LDtk software. See LDtk's World documentation.

Although the feature is still experimental, we have chosen to support it as a first class integration.

  • For multi world projects, we will export all the worlds as their own assets, with the appropriate levels, layers, etc as sub assets.
  • For single world projects, we add the identifier of "World", and clone the Iid of the project in order to build our World asset.

Naming Collisions

Unfortunately, there are many name collisions between the nomenclature used in Bevy and LDtk. Especially (but not exclusively):

  • World
  • Level
  • Layer
  • Entity

I will endeavor to refer to objects in Bevy as ECS objects, i.e. an ECS entity or ECS world when referring to objects from the Bevy ecosystem, and LDtk objects for things either from this library or LDtk itself, i.e. an LDtk entity or LDtk world.

Users are recommended to use the use ... as ... pattern in their own code when importing these types to help avoid any pitfalls.

For example, to import the LDtk Entity asset, I recommend importing the type as such:

use bevy_ldtk_asset::entity::Entity as EntityAsset;

Getting Started

Dependencies

This project depends on the Bevy engine, and will therefore inherit its dependencies. See Installing OS Dependencies from Bevy's documentation for instructions.

Installing

You can add this plugin to your project using Cargo:

cargo add bevy_ldtk_asset # from within your project directory

Or by adding bevy_ldtk_asset to your Cargo.toml file dependencies section:

[dependencies]
bevy_ldtk_asset = "0.6"

Help

Please report any issues to me via my GitHub page: github or by filing an issue: bevy_ldtk_asset issues

Authors

stinkytoe github email

Version History

  • 0.6.0
    • Release for Bevy 0.15.0
  • 0.5.1:
    • Bug fixes and small redesigns
  • 0.5.0:
    • Working release with Bevy 0.15.0-rc3 release candidate
  • 0.4 and prior:
    • archived...

Capabilities

  • Single World and Multi World projects
  • External Level Files
  • Aseprite Files #20
  • Table of Contents export
  • Layer Definitions
  • Entity Definitions
  • Tileset Definitions
  • Enum Definitions
  • Nine-Slice Borders for Entities
  • ✘Embedded Atlas #35

Compatibility

bevy_ldtk_asset bevy LDtk
0.6.0 0.15.0 1.5.3
0.5.1 0.15.0-rc.3 1.5.3
0.5.0 0.15.0-rc.3 1.5.3

License

This project is dual-licensed under either the MIT or Apache-2.0 license:

MIT License (LICENSE-MIT or http://opensource.org/licenses/MIT)

Apache License, Version 2.0 (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)

Acknowledgments

This project would not exist without the awesome efforts of the Bevy team, and Deepknight of Deepknight Games!

bevy

LDtk

Dependencies

~39–72MB
~1.5M SLoC