Closes #96
Closes #108
This is a pretty major change internally. If you're reading this and want to help me out, please update your games to this branch and let me know here whether or not there are any issues. I would like this to be the final PR before releasing 0.4, and I would like to release 0.4 very soon.
bevy_ecs_ldtk = { git = "https://github.com/Trouv/bevy_ecs_ldtk", branch = "feat/respawn" }
The scheduling has been completely reworked, and some systems have been significantly changed as a result. However, this is definitely an improvement. Many frame-delay issues are addressed by this rework, and hot reloading works again. This change was assisted by a new Respawn
component, which can work on world entities and level entities. As a bonus, users can use the Respawn
component in their games. I imagine this will mostly be used to restart levels.
The main point of this rework is to be more careful about having stage separation between commands-sensitive, order-sensitive systems. If one adds a particular component to entities, and another filters for those additions, there needs to be a stage barrier between them. Most importantly, if one despawns entities, and another spawns similar entities, there needs to be stage barrier between them. This last point was the main cause for a lot of bugs since updating to 0.8 and the bevy_ecs_tilemap
rewrite.
One drawback here is that there's a new stage between update and post-update: LdtkStage::Clean
. It's important that this goes before PostUpdate
, since it despawns bevy_ecs_tilemap
entities, which need to be further cleaned up in PostUpdate
. It's also important that this goes after Update
so that users can use Respawn
and Worldly
components without experiencing frame-delay or undefined behavior, and without having to worry about doing anything special with their scheduling. This isn't ideal, but I think it's a small price to pay. Besides, stageless is just around the corner.
Use cases targeted
- Spawning LdtkWorldBundle in startup system
- Selecting levels with LevelSelection
- Selecting levels with LevelSet
- Spawning LdtkWorldBundle in non-startup system (State::on_enter)
- Selecting levels with LevelSelection
- Selecting levels with LevelSet
- Spawning LdtkWorldBundle with an already-loaded LdtkAsset handle
- Hot reloading levels
- Respawning world with
Respawn
component
- Respawning level with
Respawn
component
New schedule (updated c5984fded3e875a42d9daa1e238b3ad964ac8a7a)
- Stage PreUpdate
- LdtkAsset processor system
- Reads AssetEvent::Modified and adds
Respawn
components to entities with those handles
- level spawn system
- For any new placeholder level entities, or any that have
Respawn
components, spawn their contents normally
- Stage LdtkStage::ProcessApi (between update and post update)
- worldly adoption system
- Have the grandparents of worldly entities adopt them (no change)
- Needs to be after Update for frame delay reasons
- LevelSelection system
- Updates LevelSet components according to LevelSelection values
- Needs to be after Update and before the LevelSet system for frame delay reasons
- LevelSet system
- For any world entities whose LevelSets have changed, or that have
Respawn
components, spawn/despawn placeholder level entities as children accordingly
Respawn
cleanup system
- Exclusive system at the end of the stage
- For
Handle<LdtkAsset>
entities with Respawn
components, despawns all of their children with Worldly
or Handle<LdtkLevel>
components
- For
Handle<LdtkLevel>
entities with Respawn
components, despawns their descendants.
- Needs to be after the LevelSet system for frame delay reasons, but before PostUpdate to appease bevy_ecs_tilemap cleanup
Known issues (to be fixed or promoted)
- When using
Respawn
on a world where a Worldly
entity has the only handle to a particular asset via #[sprite_bundle(...)]
, that asset unloads.