Trouv / bevy_ecs_ldtk

ECS-friendly ldtk plugin for bevy, leveraging bevy_ecs_tilemap
Other
630 stars 74 forks source link

Implementing Chunk Loading through Levels #268

Closed PraxTube closed 7 months ago

PraxTube commented 7 months ago

I am currently trying to implement chunking loading and it works fairly alright by using levels (based on this example). However, I have to get the iids of each level in the ldtk project, which is somewhat inconvenient. Each level is a fixed size (32 x 32 tiles), so I can definitely automate this process somehow. I was just wondering if there are any other ways except the level iids to fetch a level of a ldtk project.

Perhaps this is not what ldtk is intended for in the first place, which might lead to the XY Problem here, so let me clarify what I would like to do: I have a world that is fairly big, so I can definitely not load it all at once. Given that I have a grid world I can easily implement chunking, however this doesn't play too nicely with ldtk (at least I don't know how, which is why I am here). Is it not supposed to be used in this way? I mean I can just fetch the iids and write them into an array, but this feels like a very hacky solution.

Any advise is appreciated.

Trouv commented 7 months ago

There are other ways to fetch levels, and actually you might not need to do it yourself at all in your use case. There is the LevelSelection resource, which allows you to select a level via its identifier, iid, indices, or uid. You can use the LdtkAsset (aka LdtkProject on main) asset to try and find the level iid of a level from one of these other selectors:

// 0.8
let level_iid_for_uid = ldtk_asset.get_level(&LevelSelection::Uid(10)).unwrap().iid;

// main/0.9
let level_iid_for_uid = ldtk_project.find_level_by_level_selection(&LevelSelection::Uid(10)).unwrap().iid;

However, depending on the game you're making, it sounds like you might have a good use case for "load level neighbors". If you use LevelSelection as a bevy resource to select the level your player is currently on, then use the LdtkSettings resource like the following code snippet, the plugin will spawn the level you selected and all of its neighbors.

app.insert_resource(LdtkSettings {
    level_spawn_behavior: LevelSpawnBehavior::UseWorldTranslation { load_level_neighbors: true },
    ..default()
});

Then updating the level selection would just be a matter of figuring out if the player has traversed to one of the neighbor levels and setting that as the new LevelSelection. The platformer example does exactly that.

I will give you this warning though. Currently, the plugin will load all of the LDtk data into memory, even the levels you don't have currently spawned, even if you are using external level files. It won't have everything spawned at once obviously - but your entire project json will be in the asset store. If you're expecting it to load level data as needed rather than just spawn as needed, that isn't the current behavior.

PraxTube commented 7 months ago

Oh wow awesome! That's exactly what I was looking for.

I will give you this warning though. Currently, the plugin will load all of the LDtk data into memory, even the levels you don't have currently spawned, even if you are using external level files. It won't have everything spawned at once obviously - but your entire project json will be in the asset store. If you're expecting it to load level data as needed rather than just spawn as needed, that isn't the current behavior.

Yeah that makes sense. I am using a custom asset loader to preload all assets, so this is totally fine. Thanks for the warning, I will keep it in mind :) But it sounds like you plan to change this in the future?

Trouv commented 7 months ago

But it sounds like you plan to change this in the future?

Very loose plans yeah. It should be doable with some of the recent refactors to the asset types. Just haven't given it enough thought to land on a good design