Respawn Levels and Worlds
Internally, bevy_ecs_ldtk
uses a Respawn
component on worlds and levels to assist in the spawning process.
This can be leveraged by users to implement a simple level restart feature, or an even more heavy-handed world restart feature.
This code is from the collectathon
cargo example.
Respawn the world
To respawn the world, get the world's Entity
and insert the Respawn
component to it.
This is especially easy if, like most users, you only have one world in your game.
#![allow(unused)] fn main() { use bevy::prelude::*; use bevy_ecs_ldtk::prelude::*; fn respawn_world( mut commands: Commands, ldtk_projects: Query<Entity, With<Handle<LdtkProject>>>, input: Res<ButtonInput<KeyCode>>, ) { if input.just_pressed(KeyCode::KeyR) { commands.entity(ldtk_projects.single()).insert(Respawn); } } }
Note that this will respawn worldly entities too.
Respawn the currently-selected level
Respawning a level works similarly to respawning the world.
Get the level's Entity
and insert the Respawn
component to it.
The optimal strategy for finding the level entity can differ depending on the game.
For example, if the game should only spawn one level at a time, operate under that assumption and query for the only LevelIid
entity.
#![allow(unused)] fn main() { use bevy::prelude::*; use bevy_ecs_ldtk::prelude::*; fn respawn_only_level( mut commands: Commands, levels: Query<Entity, With<LevelIid>>, input: Res<ButtonInput<KeyCode>> ) { if input.just_pressed(KeyCode::KeyL) { commands.entity(levels.single()).insert(Respawn); } } }
If the game spawns multiple levels and you want the one specified in the LevelSelection
, you may need a more complex strategy.
In the collectathon
cargo example, the LevelSelection
is always assumed to be of the Iid
variety.
If you share this assumption, get the LevelIid
from the LevelSelection
and then search for the matching level entity.
#![allow(unused)] fn main() { use bevy::prelude::*; use bevy_ecs_ldtk::prelude::*; fn respawn_level( mut commands: Commands, level_selection: Res<LevelSelection>, levels: Query<(Entity, &LevelIid)>, input: Res<ButtonInput<KeyCode>>, ) { if input.just_pressed(KeyCode::KeyL) { let level_selection_iid = match level_selection.as_ref() { LevelSelection::Iid(iid) => iid, _ => panic!("level should always be selected by iid in this example"), }; for (level_entity, level_iid) in levels.iter() { if level_iid == level_selection_iid { commands.entity(level_entity).insert(Respawn); } } } } }
However, if you cannot make the same assumption, access the LdtkProject
asset data and search for the level matching your LevelSelection
.
There is a method on LdtkProject
to perform this search.
#![allow(unused)] fn main() { use bevy::prelude::*; use bevy_ecs_ldtk::prelude::*; fn respawn_level( mut commands: Commands, level_selection: Res<LevelSelection>, levels: Query<(Entity, &LevelIid)>, input: Res<ButtonInput<KeyCode>>, ldtk_projects: Query<&Handle<LdtkProject>>, ldtk_project_assets: Res<Assets<LdtkProject>>, ) { if input.just_pressed(KeyCode::KeyL) { if let Some(only_project) = ldtk_project_assets.get(ldtk_projects.single()) { let level_selection_iid = LevelIid::new( only_project .find_raw_level_by_level_selection(&level_selection) .expect("spawned level should exist in project") .iid .clone(), ); for (level_entity, level_iid) in levels.iter() { if level_selection_iid == *level_iid { commands.entity(level_entity).insert(Respawn); } } } } } }
Note that, unlike respawning the world, respawning the level will not respawn any worldly entities.