Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs: write *Game Logic Integration* chapter of the book #279

Merged
merged 10 commits into from
Dec 13, 2023
Prev Previous commit
Next Next commit
docs: write 'Post-processing plugin-spawned entities' section
  • Loading branch information
Trouv committed Dec 10, 2023
commit 6ab7df17b4fa5e874f5be2e79daa4108915e5960
52 changes: 50 additions & 2 deletions book/src/explanation/game-logic-integration.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,55 @@ This approach is suitable for many common, simple use cases.
There's also room for more granular, component-level customization within some of the attributes, like `#[with(...)]` or `#[from_entity_instance]`.
Of course, the traits can also be manually implemented for the even-more custom cases.

## Post-processing plugin-added entities
## Post-processing plugin-spawned entities
There are still many cases where `LdtkEntity`/`LdtkIntCell` registration is insufficient.
Perhaps you need to spawn children of the entity, or need access to more resources in the `World`.
For these more demanding cases, post-processing plugin-spawned entities in a custom system is always an option.

## A combined approach - the blueprint pattern
If an LDtk entity does not have a matching `LdtkEntity` registration, it will be spawned with an `EntityInstance` component by default.
This component contains the raw LDtk data for that entity.
Querying for newly-spawned `EntityInstance` entities can be a good starting point for implementing your own custom spawning logic.
Intgrid tiles have similar behavior, except their default component is `IntGridCell`, which simply contains the IntGrid value for that tile.

```rust,no_run
# use bevy::prelude::*;
# use bevy_ecs_ldtk::prelude::*;
#[derive(Default, Component)]
struct PlayerChild;

#[derive(Default, Component)]
struct Player;

fn process_player(
mut commands: Commands,
new_entity_instances: Query<(Entity, &EntityInstance, &Transform), Added<EntityInstance>>,
assets: Res<AssetServer>,
)
{
for (entity, entity_instance, transform) in new_entity_instances.iter() {
if entity_instance.identifier == "Player".to_string() {
commands
.entity(entity)
.insert(Player)
.insert(SpriteBundle {
texture: assets.load("player.png"),
transform: *transform,
..default()
})
.with_children(|commands| {
commands.spawn(PlayerChild);
});
}
}
}
```

This approach makes spawning entities from LDtk just as powerful and customizable as a Bevy system, because that's all it is.
`LdtkEntity` and `LdtkIntCell` ultimately make some assumptions about what data from the LDtk asset and the Bevy world you will need to spawn your entity, which post-processing avoids.
However, there are some pretty obvious ergonomics issues to this strategy compared to using registration:
- You need to manually filter `EntityInstance`s for the desired LDtk entity identifier.
- You need to manually perform the iteration of the query.
- If you need the associated layer data, or tileset image, or tileset definition, you need to manually access these assets.
- You need to be careful not to overwrite the plugin-provided `Transform` component.

## A combined approach - the blueprint pattern