#bevy-plugin #tile #bevy #2d #gamedev #map-editor

bevy_ldtk

用于读取LDtk 2D瓦片地图格式的Bevy插件

13个版本 (4个重大更新)

0.5.0 2021年4月19日
0.4.2 2021年3月10日
0.3.1 2021年2月28日
0.3.0 2021年1月31日
0.0.1 2021年1月3日

#11 in #map-editor

每月 36 次下载

自定义许可证

140KB
563

bevy_ldtk

Crates.io Docs.rs Katharos License

screenshot

( 瓦片集来自 Adam Saltsman 的 "Cavernas" )

用于加载LDtk瓦片地图的Bevy插件。

维护说明: 由于我们在内部转向使用Bevy Retro及其LDtk地图加载器,因此我们将仅对此库进行小范围修复。尽管如此,我们仍然欢迎社区提交功能或修复的pull requests!

许可证

Bevy LDtk遵循Katharos许可证,该许可证对您使用它的方式施加某些限制。请在使用Bevy LDtk进行项目之前阅读并理解这些条款。

使用方法

use bevy::prelude::*;
use bevy_ldtk::*;

fn main() {
    App::build()
        .add_plugins(DefaultPlugins)
        .add_plugin(LdtkPlugin)
        .add_startup_system(setup.system())
        .run();
}

fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
    // Enable hot reload
    asset_server.watch_for_changes().unwrap();

    commands
        // Spawn the map
        .spawn()
        .insert_bundle(LdtkMapBundle {
            map: asset_server.load("map1.ldtk"),
            config: LdtkMapConfig {
                set_clear_color: true,
                scale: 1.0,
                level: std::env::args()
                    .nth(2)
                    .map(|x| x.parse().unwrap())
                    .unwrap_or(0),
                center_map: false,
            },
            ..Default::default()
        });

    // And the camera
    commands
        .spawn()
        .insert_bundle(OrthographicCameraBundle::new_2d());
}

当地图层被实例化时,最底层的层在LdtkMapBundle's Transform组件的变换坐标处实例化。底层之后的每个层在Z轴上向上放置一个单位。为了使玩家等的精灵出现在渲染的地图上方,它们的Z轴平移必须高于地图变换+您希望它出现在其上的层编号。

LDtk版本

LDtk版本 插件版本
0.8.1 0.4, 0.5
0.7.0 0.2, 0.3

Bevy版本

Bevy版本 插件版本
0.4 0.2, 0.3, 0.4
0.5 0.5
master 未官方支持,但可能工作

功能

  • 一个高效的渲染器,每个地图层只使用4个顶点,并在GPU上排列瓦片
  • 支持通过Bevy资产服务器集成进行热重载
  • 代码注释详尽,以帮助其他希望了解如何制作自己的瓦片地图渲染器的人。

注意事项

此插件处于相对早期阶段,但对于许多基本地图来说仍然相当有用

  • 许多功能尚未支持,包括
    • 带间隔的瓦片集
    • 单独文件中的关卡
  • 偶尔在瓦片之间会出现一些轻微的渲染伪影。( #1 )目前还不确定是什么原因造成的。非常感谢任何有渲染经验的帮助!

提取地图信息

您可以从LDtk JSON地图数据中提取游戏所需的任何信息。以下是一个示例,展示如何实例化玩家。

fn spawn_player(
    mut commands: Commands,
    printed_maps: Local<Vec<Entity>>,
    query: Query<(Entity, &Handle<LdtkMap>)>,
    map_assets: Res<Assets<LdtkMap>>,
    asset_server: Res<AssetServer>,
    mut color_materials: ResMut<Assets<ColorMaterial>>,
) {
    for (ent, handle) in query.iter() {
        // Skip any maps we have already printed the spawn location for
        if printed_maps.contains(&ent) {
            continue;
        }

        // If the map asset has finished loading
        if let Some(map) = map_assets.get(handle) {
            // This is the default level, but if you spawned a different level, put that ID here
            let level_idx = 0;

            // Get the level from the project
            let level = &map.project.levels[level_idx];

            // Find the entities layer
            let entities_layer = level
                .layer_instances
                .as_ref() // get a reference to the layer instances
                .unwrap() // Unwrap the option ( this could be None, if there are no layers )
                .iter() // Iterate over the layers
                .filter(|&x| x.__identifier == "Entities") // Filter on the name of the layer
                .next() // Get it
                .unwrap(); // Unwrap it ( would be None if it could not find a layer "MyEntities" )

            // Get the specific entity you want
            let player_start = entities_layer
                .entity_instances
                .iter() // Iterate over our entities in the layer
                .filter(|x| x.__identifier == "Player_Spawn") // Find the one we want
                .next() // Get it
                .unwrap(); // Unwrap it

            // Get the number of layers in the map and add one to it: this is how high we need to
            // spawn the player so that he is on top of all the maps
            let player_z = level.layer_instances.as_ref().unwrap().len() as f32 + 1.0;

            // Spawn the entity!
            commands.spawn().insert_bundle(SpriteBundle {
                // Set your sprite stuff
                transform: Transform::from_xyz(
                    // The player x position is the entity's x position from the map data
                    player_start.px[0] as f32,
                    // The player y position is the entity's y position from the map data, but
                    // multiplied by negative one because in the LDtk map +y means down and not up.
                    player_start.px[1] as f32 * -1.0,
                    // Spawn the player with the z value we determined earlier
                    player_z,
                ),
                material: color_materials.add(ColorMaterial {
                    texture: Some(asset_server.load("character.png")),
                    ..Default::default()
                }),
                ..Default::default()
            });
        }
    }
}

依赖关系

~29–73MB
~596K SLoC