Skip to content

Commit

Permalink
docs: write *Respawn levels and worlds* chapter of book (#289)
Browse files Browse the repository at this point in the history
This chapter demonstrates usage of the `Respawn` component. It uses code
from the new `collectathon` cargo example. This makes some docs in the
api reference redundant, so those have been replaced with a link to the
book.
  • Loading branch information
Trouv authored Jan 31, 2024
1 parent 32dfb85 commit 55ed30f
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 7 deletions.
1 change: 1 addition & 0 deletions .github/workflows/release-please.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ jobs:
book/src/explanation/game-logic-integration.md
book/src/explanation/level-selection.md
book/src/explanation/anatomy-of-the-world.md
book/src/how-to-guides/respawn-levels-and-worlds.md
src/lib.rs
src/components/mod.rs
src/components/level_set.rs
Expand Down
2 changes: 1 addition & 1 deletion book/src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
- [Process Entities Further with Blueprints]()
- [Combine Tiles into Larger Entities]()
- [Create Bevy Relations from LDtk Entity References](how-to-guides/create-bevy-relations-from-ldtk-entity-references.md)
- [Respawn Levels and Worlds]()
- [Respawn Levels and Worlds](how-to-guides/respawn-levels-and-worlds.md)
- [Animate Tiles]()
- [Camera Logic]()
- [Implement Fit-Inside Camera]()
Expand Down
78 changes: 78 additions & 0 deletions book/src/how-to-guides/respawn-levels-and-worlds.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# Respawn Levels and Worlds
Internally, `bevy_ecs_ldtk` uses a [`Respawn`](https://docs.rs/bevy_ecs_ldtk/0.8.0/bevy_ecs_ldtk/prelude/struct.Respawn.html) component on worlds and levels to assist in the spawning process. <!-- x-release-please-version -->
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.
```rust,no_run
# use bevy::prelude::*;
# use bevy_ecs_ldtk::prelude::*;
{{ #include ../../../examples/collectathon/respawn.rs:33:41 }}
```

Note that this *will* respawn [worldly](../explanation/anatomy-of-the-world.html#worldly-entities) 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.
```rust,no_run
# use bevy::prelude::*;
# use bevy_ecs_ldtk::prelude::*;
fn respawn_only_level(
mut commands: Commands,
levels: Query<Entity, With<LevelIid>>,
input: Res<Input<KeyCode>>
) {
if input.just_pressed(KeyCode::L) {
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.
```rust,no_run
# use bevy::prelude::*;
# use bevy_ecs_ldtk::prelude::*;
{{ #include ../../../examples/collectathon/respawn.rs:13:31 }}
```

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.
```rust,no_run
# use bevy::prelude::*;
# use bevy_ecs_ldtk::prelude::*;
{{ #include ../../../examples/collectathon/respawn.rs:13:17 }}
ldtk_projects: Query<&Handle<LdtkProject>>,
ldtk_project_assets: Res<Assets<LdtkProject>>,
) {
if input.just_pressed(KeyCode::L) {
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](../explanation/anatomy-of-the-world.html#worldly-entities) entities.
9 changes: 3 additions & 6 deletions src/components/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -301,12 +301,9 @@ impl From<&LayerInstance> for LayerMetadata {

/// [Component] that indicates that an LDtk level or world should respawn.
///
/// Inserting this component on an entity with either [`Handle<LdtkProject>`] or [`LevelIid`]
/// components will cause it to respawn.
/// This can be used to implement a simple level-restart feature.
/// Internally, this is used to support the entire level spawning process
///
/// [`Handle<LdtkProject>`]: crate::assets::LdtkProject
/// For more details and example usage, please see the
/// [*Respawn Levels and Worlds*](https://trouv.github.io/bevy_ecs_ldtk/v0.8.0/how-to-guides/respawn-levels-and-worlds.html) <!-- x-release-please-version -->
/// chapter of the `bevy_ecs_ldtk` book.
#[derive(Copy, Clone, Eq, PartialEq, Debug, Default, Hash, Component, Reflect)]
#[reflect(Component)]
pub struct Respawn;
Expand Down

0 comments on commit 55ed30f

Please sign in to comment.