diff --git a/Cargo.toml b/Cargo.toml index 51527008..6a9368f4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,8 +15,10 @@ members = ["macros"] [dependencies] bevy_ecs_ldtk_macros = { version = "0.10.0", optional = true, path = "macros" } -bevy_ecs_tilemap = { version = "0.14.0", default-features = false} -bevy = { version = "0.14", default-features = false, features = ["bevy_sprite"] } +bevy_ecs_tilemap = { version = "0.15.0", default-features = false } +bevy = { version = "0.15", default-features = false, features = [ + "bevy_sprite", +] } derive-getters = "0.3.0" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" @@ -27,11 +29,11 @@ derive_more = "0.99.17" path-clean = "1.0.1" [dev-dependencies] -bevy = "0.14" -bevy_rapier2d = "0.27.0" +bevy = "0.15" +bevy_rapier2d = "0.28.0" fake = { version = "2.8.0", features = ["uuid"] } rand = "0.8" -bevy-inspector-egui = "0.25" +bevy-inspector-egui = "0.28" [features] default = ["derive", "render", "internal_levels"] diff --git a/book/src/SUMMARY.md b/book/src/SUMMARY.md index c55d8c52..212037c4 100644 --- a/book/src/SUMMARY.md +++ b/book/src/SUMMARY.md @@ -32,5 +32,6 @@ - [Migration Guides](how-to-guides/migration-guides/README.md) - [Migrate from 0.8 to 0.9](how-to-guides/migration-guides/migrate-from-0.8-to-0.9.md) - [Migrate from 0.9 to 0.10](how-to-guides/migration-guides/migrate-from-0.9-to-0.10.md) + - [Migrate from 0.10 to 0.11](how-to-guides/migration-guides/migrate-from-0.10-to-0.11.md) --- [API Reference](api-reference.md). diff --git a/book/src/explanation/anatomy-of-the-world.md b/book/src/explanation/anatomy-of-the-world.md index e9f96876..b4975092 100644 --- a/book/src/explanation/anatomy-of-the-world.md +++ b/book/src/explanation/anatomy-of-the-world.md @@ -40,8 +40,8 @@ Naturally, this can only occur in Tile/AutoTile layers (or IntGrid layers with A ## Level backgrounds LDtk allows you to supply a background color and a background image for individual levels. `bevy_ecs_ldtk` renders these by default. -The background color is spawned as a normal bevy [`SpriteBundle`](https://docs.rs/bevy/latest/bevy/prelude/struct.SpriteBundle.html), as a child of the level entity. -The background image, if it exists, is also spawned as a `SpriteBundle`. +The background color is spawned as a normal bevy [`Sprite`](https://docs.rs/bevy/latest/bevy/prelude/struct.Sprite.html), as a child of the level entity. +The background image, if it exists, is also spawned as a `Sprite`. These background sprites can be disabled (not spawned) using the settings resource [`LdtkSettings`](https://docs.rs/bevy_ecs_ldtk/0.10.0/bevy_ecs_ldtk/prelude/struct.LdtkSettings.html): ```rust,no_run diff --git a/book/src/explanation/game-logic-integration.md b/book/src/explanation/game-logic-integration.md index 2b789e6d..e85b2bf4 100644 --- a/book/src/explanation/game-logic-integration.md +++ b/book/src/explanation/game-logic-integration.md @@ -27,14 +27,14 @@ struct Player; #[derive(Default, Bundle, LdtkEntity)] struct PlayerBundle { player: Player, - #[sprite_bundle] - sprite_bundle: SpriteBundle, + #[sprite] + sprite: Sprite, } ``` How does `LdtkEntity`/`LdtkIntCell` construct the bundle when derived? Without any intervention, the bundle's fields are constructed using the bundle's `Default` implementation. -However, various attributes are available to override this behavior, like `#[sprite_bundle]` in the above example. +However, various attributes are available to override this behavior, like `#[sprite]` in the above example. This attribute gives the entity a sprite using the tileset in its LDtk editor visual. For documentation about all the available attributes, check out the API reference for these traits: - [`LdtkEntity`](https://docs.rs/bevy_ecs_ldtk/0.10.0/bevy_ecs_ldtk/app/trait.LdtkEntity.html) @@ -74,11 +74,10 @@ fn process_player( commands .entity(entity) .insert(Player) - .insert(SpriteBundle { - texture: assets.load("player.png"), - transform: *transform, - ..default() - }) + .insert(( + Sprite::from_image(assets.load("player.png")), + *transform, + )) .with_children(|commands| { commands.spawn(PlayerChild); }); @@ -121,8 +120,8 @@ struct Player; #[derive(Default, Bundle, LdtkEntity)] struct PlayerBundle { player: Player, - #[sprite_bundle] - sprite_bundle: SpriteBundle, + #[sprite] + sprite: Sprite, } fn process_player( diff --git a/book/src/how-to-guides/make-level-selection-follow-player.md b/book/src/how-to-guides/make-level-selection-follow-player.md index 9dcfbe98..6b7a73b0 100644 --- a/book/src/how-to-guides/make-level-selection-follow-player.md +++ b/book/src/how-to-guides/make-level-selection-follow-player.md @@ -25,7 +25,7 @@ Use the transforms of the spawned levels and width/height info from the level's To access the level asset data, you first need to access the project asset data. -Assuming you only have one project, query for the only `Handle` entity and look up its asset data in the `LdtkProject` asset store. +Assuming you only have one project, query for the only `LdtkProjectHandle` entity and look up its asset data in the `LdtkProject` asset store. Then, get the raw level data for every spawned level using the level entity's `LevelIid` component (there is a provided method for this). ```rust,no_run diff --git a/book/src/how-to-guides/migration-guides/migrate-from-0.10-to-0.11.md b/book/src/how-to-guides/migration-guides/migrate-from-0.10-to-0.11.md new file mode 100644 index 00000000..2dfbc130 --- /dev/null +++ b/book/src/how-to-guides/migration-guides/migrate-from-0.10-to-0.11.md @@ -0,0 +1,118 @@ +# Migrate from 0.10 to 0.11 + +## Bevy upgrade +`bevy_ecs_ldtk` has upgraded to Bevy and `bevy_ecs_tilemap` version `0.15`. +A Bevy `0.15` migration guide is available on [Bevy's website](https://bevyengine.org/learn/migration-guides/0-14-to-0-15/). + +## `LdtkSpriteSheetBundle` replaced with `Sprite` +Since the `Sprite` struct in Bevy `0.15` can now store `TextureAtlas` information on its own, the use of `LdtkSpriteSheetBundle` has been replaced by a simple use of `Sprite`. The macro has changed as well, and is now named `#[sprite_sheet]`. +```rust,ignore +// 0.10 +# use bevy_ecs_ldtk::prelude::*; +# use bevy::prelude::*; +#[derive(Default, Bundle, LdtkEntity)] +struct PlayerBundle { + #[sprite_sheet_bundle] + sprite_bundle: LdtkSpriteSheetBundle, + #[grid_coords] + grid_coords: GridCoords, +} +``` +```rust,ignore +// 0.11 +# use bevy_ecs_ldtk::prelude::*; +# use bevy::prelude::*; +#[derive(Default, Bundle, LdtkEntity)] +struct PlayerBundle { + #[sprite_sheet] + sprite_sheet: Sprite, + #[grid_coords] + grid_coords: GridCoords, +} +``` + +## `SpriteBundle` also replaced with `Sprite` +When using a `SpriteBundle` with the `#[sprite_bundle]` macro, use a `Sprite` instead. The macro is now named `#[sprite]`. +```rust,ignore +// 0.10 +# use bevy_ecs_ldtk::prelude::*; +# use bevy::prelude::*; +#[derive(Bundle, LdtkEntity, Default)] +pub struct Player { + player: PlayerComponent, + health: Health, + #[sprite_bundle] + sprite_bundle: SpriteBundle, +} +``` +```rust,ignore +// 0.11 +# use bevy_ecs_ldtk::prelude::*; +# use bevy::prelude::*; +#[derive(Bundle, LdtkEntity, Default)] +pub struct Player { + player: PlayerComponent, + health: Health, + #[sprite] + sprite: Sprite, +} +``` + +## `Handle` replaced with `LdtkProjectHandle` +Handles cannot be used as components in Bevy `0.15` onward. This has two changes. +### Call `.into()` when loading a project +First, you must call `.into()` when loading the world. +```rust,ignore +// 0.10 +# use bevy_ecs_ldtk::prelude::*; +# use bevy::prelude::*; +fn setup(mut commands: Commands, asset_server: Res) { + commands.spawn(LdtkWorldBundle { + ldtk_handle: asset_server.load("my_project.ldtk"), + ..Default::default() + }); +} +``` +```rust,ignore +// 0.11 +# use bevy_ecs_ldtk::prelude::*; +# use bevy::prelude::*; +fn setup(mut commands: Commands, asset_server: Res) { + commands.spawn(LdtkWorldBundle { + ldtk_handle: asset_server.load("my_project.ldtk").into(), + ..Default::default() + }); +} +``` +### Replace usages of `Handle` +Second, uses of `Handle` in queries must be replaced with `LdtkProjectHandle`. It is enough to replace the type in the signature, as the `LdtkProjectHandle` type is a drop-in replacement for the handle. + +```rust,ignore +// 0.10 +# use bevy_ecs_ldtk::prelude::*; +# use bevy::prelude::*; +fn respawn_world( + mut commands: Commands, + ldtk_projects: Query>>, + input: Res>, +) { + if input.just_pressed(KeyCode::KeyR) { + commands.entity(ldtk_projects.single()).insert(Respawn); + } +} +``` +```rust,ignore +// 0.11 +# use bevy_ecs_ldtk::prelude::*; +# use bevy::prelude::*; +fn respawn_world( + mut commands: Commands, + ldtk_projects: Query>, + input: Res>, +) { + if input.just_pressed(KeyCode::KeyR) { + commands.entity(ldtk_projects.single()).insert(Respawn); + } +} +``` + diff --git a/book/src/how-to-guides/migration-guides/migrate-from-0.8-to-0.9.md b/book/src/how-to-guides/migration-guides/migrate-from-0.8-to-0.9.md index 395bcb5a..1a1dd56b 100644 --- a/book/src/how-to-guides/migration-guides/migrate-from-0.8-to-0.9.md +++ b/book/src/how-to-guides/migration-guides/migrate-from-0.8-to-0.9.md @@ -12,7 +12,7 @@ To update your game to LDtk 1.5.3, you should only need to install the new versi Fields on an `LdtkEntity`- or `LdtkIntCell`-derived bundle are no longer constructed from the field's `Default` implementation, but the bundle's. You may observe different behavior in `0.9` if the value for a field in your bundle's `Default` implementation differs from the field type's own `Default` implementation: -```rust,no_run +```rust,ignore # use bevy::prelude::*; # use bevy_ecs_ldtk::prelude::*; #[derive(Component)] @@ -50,7 +50,7 @@ struct MyBundle { component: MyComponentThatImplementsDefault, } ``` -```rust,no_run +```rust,ignore # use bevy_ecs_ldtk::prelude::*; # use bevy::prelude::*; # #[derive(Default, Component)] @@ -80,7 +80,7 @@ fn get_level_of_entity( } } ``` -```rust,no_run +```rust,ignore # use bevy_ecs_ldtk::prelude::*; # use bevy::prelude::*; // 0.9 @@ -114,7 +114,7 @@ fn do_some_processing_with_ldtk_data( // do something } ``` -```rust,no_run +```rust,ignore # use bevy_ecs_ldtk::prelude::*; # use bevy::prelude::*; // 0.9 @@ -135,7 +135,7 @@ let tileset_map = ldtk_project.tileset_map; let int_grid_image_handle = ldtk_project.int_grid_image_handle; let level_map = ldtk_project.level_map; ``` -```rust,no_run +```rust,ignore # use bevy_ecs_ldtk::prelude::*; # fn foo(ldtk_project: LdtkProject) { // 0.9 @@ -157,7 +157,7 @@ ldtk_asset.iter_levels(); ldtk_asset.get_level(&LevelSelection::Uid(24)); ``` -```rust,no_run +```rust,ignore # use bevy_ecs_ldtk::{prelude::*, ldtk::LdtkJson}; # fn foo(ldtk_json: LdtkJson, ldtk_project: LdtkProject) { // 0.9 @@ -215,7 +215,7 @@ fn print_level_entity(levels: Query>>) { } } ``` -```rust,no_run +```rust,ignore # use bevy_ecs_ldtk::prelude::*; # use bevy::prelude::*; // 0.9 @@ -238,7 +238,7 @@ fn print_level_uid(levels: Query>, level_assets: Res) { } } ``` -```rust,no_run +```rust,ignore # use bevy_ecs_ldtk::prelude::*; # use bevy::prelude::*; use std::any::{Any, TypeId}; @@ -387,7 +387,7 @@ fn assert_level_event_type(mut level_events: EventReader) { // 0.8 let level_selection = LevelSelection::Iid("e5eb2d73-60bb-4779-8b33-38a63da8d1db".to_string()); ``` -```rust,no_run +```rust,ignore # use bevy_ecs_ldtk::prelude::*; # fn f() { // 0.9 @@ -403,7 +403,7 @@ However, you can still construct a `LevelSelection` from a single level index us // 0.8 let level_selection = LevelSelection::Index(2); ``` -```rust,no_run +```rust,ignore # use bevy_ecs_ldtk::prelude::*; # fn f() { // 0.9 @@ -418,7 +418,7 @@ This new method can accept any iterator of strings rather than just one: // 0.8 let level_set = LevelSet::from_iid("e5eb2d73-60bb-4779-8b33-38a63da8d1db"); ``` -```rust,no_run +```rust,ignore # use bevy_ecs_ldtk::prelude::*; # fn f() { // 0.9 diff --git a/book/src/how-to-guides/migration-guides/migrate-from-0.9-to-0.10.md b/book/src/how-to-guides/migration-guides/migrate-from-0.9-to-0.10.md index f92af8cc..f782c0cc 100644 --- a/book/src/how-to-guides/migration-guides/migrate-from-0.9-to-0.10.md +++ b/book/src/how-to-guides/migration-guides/migrate-from-0.9-to-0.10.md @@ -17,7 +17,7 @@ struct PlayerBundle { grid_coords: GridCoords, } ``` -```rust,no_run +```rust,ignore // 0.10 # use bevy_ecs_ldtk::prelude::*; # use bevy::prelude::*; diff --git a/book/src/how-to-guides/respawn-levels-and-worlds.md b/book/src/how-to-guides/respawn-levels-and-worlds.md index 463f45b9..39ffb148 100644 --- a/book/src/how-to-guides/respawn-levels-and-worlds.md +++ b/book/src/how-to-guides/respawn-levels-and-worlds.md @@ -51,7 +51,7 @@ There is a method on `LdtkProject` to perform this search. # use bevy::prelude::*; # use bevy_ecs_ldtk::prelude::*; {{ #include ../../../examples/collectathon/respawn.rs:13:17 }} - ldtk_projects: Query<&Handle>, + ldtk_projects: Query<&LdtkProjectHandle>, ldtk_project_assets: Res>, ) { if input.just_pressed(KeyCode::KeyL) { diff --git a/book/src/tutorials/tile-based-game/add-gameplay-to-your-project.md b/book/src/tutorials/tile-based-game/add-gameplay-to-your-project.md index 5eefd39c..d9d58648 100644 --- a/book/src/tutorials/tile-based-game/add-gameplay-to-your-project.md +++ b/book/src/tutorials/tile-based-game/add-gameplay-to-your-project.md @@ -18,7 +18,7 @@ Derive `Default` for this component. ```rust,no_run # use bevy::prelude::*; # use bevy_ecs_ldtk::prelude::*; -{{#include ../../../../examples/tile_based_game.rs:42:52}} +{{#include ../../../../examples/tile_based_game.rs:45:55}} ``` ## Implement tile-based movement @@ -38,8 +38,8 @@ fn main() { .run(); } -{{#include ../../../../examples/tile_based_game.rs:91:93}} -{{#include ../../../../examples/tile_based_game.rs:95:109}} +{{#include ../../../../examples/tile_based_game.rs:94:96}} +{{#include ../../../../examples/tile_based_game.rs:98:112}} *player_grid_coords = destination; } } @@ -67,7 +67,7 @@ fn main() { .run(); } -{{#include ../../../../examples/tile_based_game.rs:116:126}} +{{#include ../../../../examples/tile_based_game.rs:119:129}} ``` ## Prevent tile-based movement into walls @@ -88,7 +88,7 @@ fn main() { .run(); } -{{#include ../../../../examples/tile_based_game.rs:66:72}} +{{#include ../../../../examples/tile_based_game.rs:69:75}} ``` There are a lot of ways to go about implementing the collision systems. @@ -111,12 +111,12 @@ fn main() { .run(); } -{{#include ../../../../examples/tile_based_game.rs:74:89}} +{{#include ../../../../examples/tile_based_game.rs:77:92}} ``` Now, add a system that listens for `LevelEvent::Spawned` and populates this resource. It will need access to all of the wall locations to populate the `HashSet` (`Query<&GridCoords, With>`). -It will also need access to the `LdtkProject` data to find the current level's width/height (`Query<&Handle>` and `Res>`). +It will also need access to the `LdtkProject` data to find the current level's width/height (`Query<&LdtkProjectHandle>` and `Res>`). ```rust,no_run # use bevy::prelude::*; # use bevy_ecs_ldtk::prelude::*; @@ -150,7 +150,7 @@ fn main() { .run(); } -{{#include ../../../../examples/tile_based_game.rs:128:155}} +{{#include ../../../../examples/tile_based_game.rs:131:158}} ``` Finally, update the `move_player_from_input` system to access the `LevelWalls` resource and check whether or not the player's destination is in a wall. @@ -175,7 +175,7 @@ Finally, update the `move_player_from_input` system to access the `LevelWalls` r # || self.wall_locations.contains(grid_coords) # } # } -{{#include ../../../../examples/tile_based_game.rs:91:114}} +{{#include ../../../../examples/tile_based_game.rs:94:117}} ``` With this check in place, the player should now be unable to move into walls! @@ -188,7 +188,7 @@ Similar to the `PlayerBundle`, give the `GoalBundle` its own marker component an ```rust,no_run # use bevy::prelude::*; # use bevy_ecs_ldtk::prelude::*; -{{#include ../../../../examples/tile_based_game.rs:54:64}} +{{#include ../../../../examples/tile_based_game.rs:57:67}} ``` Then, write a system that checks if the player's `GridCoords` and the goal's `GridCoords` match. @@ -212,7 +212,7 @@ fn main() { .run(); } -{{#include ../../../../examples/tile_based_game.rs:157::}} +{{#include ../../../../examples/tile_based_game.rs:160::}} ``` With this, the simple tile-based game is complete. diff --git a/book/src/tutorials/tile-based-game/spawn-your-ldtk-project-in-bevy.md b/book/src/tutorials/tile-based-game/spawn-your-ldtk-project-in-bevy.md index 95669e00..b138298b 100644 --- a/book/src/tutorials/tile-based-game/spawn-your-ldtk-project-in-bevy.md +++ b/book/src/tutorials/tile-based-game/spawn-your-ldtk-project-in-bevy.md @@ -36,7 +36,7 @@ fn main() { .run(); } -{{#include ../../../../examples/tile_based_game.rs:29:40}} +{{#include ../../../../examples/tile_based_game.rs:29:43}} ``` Finally, insert the `LevelSelection` resource to tell the plugin to spawn the first level. @@ -60,9 +60,9 @@ Now, run the game with `$ cargo run --release` to see your first level spawning You may have noticed that the Player and Goal are not rendered here. They are there, but they require a little more work to become visible. -Create a `PlayerBundle` and `GoalBundle`, each with an `LdtkSpriteSheetBundle` field. +Create a `PlayerBundle` and `GoalBundle`, each with an `sprite_sheet` field. You will develop these bundles a little bit more in the next chapter, but for now they will be similar. -Derive `LdtkEntity` for these bundles, and give the field a `#[sprite_sheet_bundle]` attribute. +Derive `LdtkEntity` for these bundles, and give the field a `#[sprite_sheet]` attribute. This trait implementation defines how these bundles should be spawned by the plugin. More specifically - they should be spawned as sprites identical to the entity's editor visual. ```rust,no_run @@ -70,14 +70,14 @@ More specifically - they should be spawned as sprites identical to the entity's # use bevy_ecs_ldtk::prelude::*; #[derive(Default, Bundle, LdtkEntity)] struct PlayerBundle { - #[sprite_sheet_bundle] - sprite_sheet_bundle: LdtkSpriteSheetBundle, + #[sprite_sheet] + sprite_sheet: Sprite, } #[derive(Default, Bundle, LdtkEntity)] struct GoalBundle { - #[sprite_sheet_bundle] - sprite_sheet_bundle: LdtkSpriteSheetBundle, + #[sprite_sheet] + sprite_sheet: Sprite, } ``` @@ -94,13 +94,13 @@ fn main() { } # #[derive(Default, Bundle, LdtkEntity)] # struct PlayerBundle { -# #[sprite_sheet_bundle] -# sprite_sheet_bundle: LdtkSpriteSheetBundle, +# #[sprite_sheet] +# sprite_sheet: Sprite, # } # #[derive(Default, Bundle, LdtkEntity)] # struct GoalBundle { -# #[sprite_sheet_bundle] -# sprite_sheet_bundle: LdtkSpriteSheetBundle, +# #[sprite_sheet] +# sprite_sheet: Sprite, # } ``` diff --git a/examples/basic.rs b/examples/basic.rs index b835c822..2258f510 100644 --- a/examples/basic.rs +++ b/examples/basic.rs @@ -14,10 +14,10 @@ fn main() { } fn setup(mut commands: Commands, asset_server: Res) { - commands.spawn(Camera2dBundle::default()); + commands.spawn(Camera2d); commands.spawn(LdtkWorldBundle { - ldtk_handle: asset_server.load("my_project.ldtk"), + ldtk_handle: asset_server.load("my_project.ldtk").into(), ..Default::default() }); } @@ -32,6 +32,6 @@ struct ComponentB; pub struct MyBundle { a: ComponentA, b: ComponentB, - #[sprite_sheet_bundle] - sprite_bundle: LdtkSpriteSheetBundle, + #[sprite_sheet] + sprite_sheet: Sprite, } diff --git a/examples/collectathon/coin.rs b/examples/collectathon/coin.rs index 0416b74c..60885c71 100644 --- a/examples/collectathon/coin.rs +++ b/examples/collectathon/coin.rs @@ -18,8 +18,8 @@ struct Coin; #[derive(Default, Bundle, LdtkEntity)] struct CoinBundle { coin: Coin, - #[sprite_sheet_bundle] - sprite_sheet: LdtkSpriteSheetBundle, + #[sprite_sheet] + sprite_sheet: Sprite, } /// Component for entities that can collect coins. diff --git a/examples/collectathon/main.rs b/examples/collectathon/main.rs index 84b09cdc..4dbbec84 100644 --- a/examples/collectathon/main.rs +++ b/examples/collectathon/main.rs @@ -26,11 +26,15 @@ fn main() { } fn setup(mut commands: Commands, asset_server: Res) { - let mut camera = Camera2dBundle::default(); - camera.projection.scale = 0.5; - commands.spawn(camera); + commands.spawn(( + Camera2d, + OrthographicProjection { + scale: 0.5, + ..OrthographicProjection::default_2d() + }, + )); - let ldtk_handle = asset_server.load("collectathon.ldtk"); + let ldtk_handle = asset_server.load("collectathon.ldtk").into(); commands.spawn(LdtkWorldBundle { ldtk_handle, diff --git a/examples/collectathon/player.rs b/examples/collectathon/player.rs index bf65b15a..027e4368 100644 --- a/examples/collectathon/player.rs +++ b/examples/collectathon/player.rs @@ -22,8 +22,8 @@ struct PlayerBundle { wallet: Wallet, #[worldly] worldly: Worldly, - #[sprite_sheet_bundle] - sprite_sheet: LdtkSpriteSheetBundle, + #[sprite_sheet] + sprite_sheet: Sprite, } const MOVEMENT_SPEED: f32 = 96.; @@ -51,7 +51,7 @@ fn move_player( if movement != Vec2::ZERO { player_transform.translation += - movement.extend(0.) * MOVEMENT_SPEED * time.delta_seconds(); + movement.extend(0.) * MOVEMENT_SPEED * time.delta_secs(); } } } @@ -59,7 +59,7 @@ fn move_player( fn level_selection_follow_player( players: Query<&GlobalTransform, With>, levels: Query<(&LevelIid, &GlobalTransform)>, - ldtk_projects: Query<&Handle>, + ldtk_projects: Query<&LdtkProjectHandle>, ldtk_project_assets: Res>, mut level_selection: ResMut, ) { diff --git a/examples/collectathon/respawn.rs b/examples/collectathon/respawn.rs index 25542796..8adea58d 100644 --- a/examples/collectathon/respawn.rs +++ b/examples/collectathon/respawn.rs @@ -32,7 +32,7 @@ fn respawn_level( fn respawn_world( mut commands: Commands, - ldtk_projects: Query>>, + ldtk_projects: Query>, input: Res>, ) { if input.just_pressed(KeyCode::KeyR) { diff --git a/examples/field_instances/enemy.rs b/examples/field_instances/enemy.rs index 048ebf1a..dcd850db 100644 --- a/examples/field_instances/enemy.rs +++ b/examples/field_instances/enemy.rs @@ -14,8 +14,8 @@ pub struct EnemyBundle { equipment_drops: EquipmentDrops, #[with(UnresolvedMotherRef::from_mother_field)] unresolved_mother: UnresolvedMotherRef, - #[sprite_sheet_bundle] - sprite_sheet_bundle: LdtkSpriteSheetBundle, + #[sprite_sheet] + sprite_sheet: Sprite, } fn name_from_field(entity_instance: &EntityInstance) -> Name { diff --git a/examples/field_instances/level_title.rs b/examples/field_instances/level_title.rs index 62f52698..c17f3be6 100644 --- a/examples/field_instances/level_title.rs +++ b/examples/field_instances/level_title.rs @@ -12,7 +12,7 @@ pub struct LevelTitle(String); pub fn set_level_title_to_current_level( mut level_events: EventReader, levels: Query<&LevelIid>, - projects: Query<&Handle>, + projects: Query<&LdtkProjectHandle>, project_assets: Res>, mut current_level_title: ResMut, ) { diff --git a/examples/field_instances/main.rs b/examples/field_instances/main.rs index 6efd91e9..7fffda4c 100644 --- a/examples/field_instances/main.rs +++ b/examples/field_instances/main.rs @@ -42,7 +42,7 @@ fn main() { .init_resource::() .add_systems( Update, - level_title::set_level_title_to_current_level.run_if(on_event::()), + level_title::set_level_title_to_current_level.run_if(on_event::), ) .register_ldtk_entity::("Enemy") // The rest of this is bevy_inspector_egui boilerplate @@ -55,9 +55,9 @@ fn main() { } fn setup(mut commands: Commands, asset_server: Res) { - commands.spawn(Camera2dBundle::default()); + commands.spawn(Camera2d); - let ldtk_handle = asset_server.load("field_instances.ldtk"); + let ldtk_handle = asset_server.load("field_instances.ldtk").into(); commands.spawn(LdtkWorldBundle { ldtk_handle, diff --git a/examples/level_set.rs b/examples/level_set.rs index 803dc890..f0c1a567 100644 --- a/examples/level_set.rs +++ b/examples/level_set.rs @@ -37,12 +37,12 @@ const LEVEL_IIDS: [&str; 8] = [ ]; fn setup(mut commands: Commands, asset_server: Res) { - commands.spawn(Camera2dBundle::default()); + commands.spawn(Camera2d); let level_set = LevelSet::from_iids(LEVEL_IIDS); commands.spawn(LdtkWorldBundle { - ldtk_handle: asset_server.load("WorldMap_Free_layout.ldtk"), + ldtk_handle: asset_server.load("WorldMap_Free_layout.ldtk").into(), level_set, transform: Transform::from_xyz(-256., -144., 0.), ..Default::default() diff --git a/examples/platformer/camera.rs b/examples/platformer/camera.rs index e3a52d5f..40cc2ec3 100644 --- a/examples/platformer/camera.rs +++ b/examples/platformer/camera.rs @@ -16,7 +16,7 @@ pub fn camera_fit_inside_current_level( >, player_query: Query<&Transform, With>, level_query: Query<(&Transform, &LevelIid), (Without, Without)>, - ldtk_projects: Query<&Handle>, + ldtk_projects: Query<&LdtkProjectHandle>, level_selection: Res, ldtk_project_assets: Res>, ) { diff --git a/examples/platformer/enemy.rs b/examples/platformer/enemy.rs index cf4e5768..effb1f11 100644 --- a/examples/platformer/enemy.rs +++ b/examples/platformer/enemy.rs @@ -9,8 +9,8 @@ pub struct Enemy; #[derive(Clone, Default, Bundle, LdtkEntity)] pub struct MobBundle { - #[sprite_sheet_bundle] - pub sprite_sheet_bundle: LdtkSpriteSheetBundle, + #[sprite_sheet] + pub sprite_sheet: Sprite, #[from_entity_instance] pub collider_bundle: ColliderBundle, pub enemy: Enemy, diff --git a/examples/platformer/game_flow.rs b/examples/platformer/game_flow.rs index dc6fbdc8..3aec7a9f 100644 --- a/examples/platformer/game_flow.rs +++ b/examples/platformer/game_flow.rs @@ -1,12 +1,20 @@ use crate::player::Player; use bevy::prelude::*; use bevy_ecs_ldtk::prelude::*; +use bevy_rapier2d::prelude::*; -pub fn setup(mut commands: Commands, asset_server: Res) { - let camera = Camera2dBundle::default(); - commands.spawn(camera); +pub fn setup( + mut commands: Commands, + asset_server: Res, + mut rapier_config: Query<&mut RapierConfiguration>, +) { + commands.spawn(Camera2d); + + rapier_config.single_mut().gravity = Vec2::new(0.0, -2000.0); - let ldtk_handle = asset_server.load("Typical_2D_platformer_example.ldtk"); + let ldtk_handle = asset_server + .load("Typical_2D_platformer_example.ldtk") + .into(); commands.spawn(LdtkWorldBundle { ldtk_handle, ..Default::default() @@ -17,7 +25,7 @@ pub fn update_level_selection( level_query: Query<(&LevelIid, &Transform), Without>, player_query: Query<&Transform, With>, mut level_selection: ResMut, - ldtk_projects: Query<&Handle>, + ldtk_projects: Query<&LdtkProjectHandle>, ldtk_project_assets: Res>, ) { for (level_iid, level_transform) in &level_query { diff --git a/examples/platformer/main.rs b/examples/platformer/main.rs index 97118d60..89568ce5 100644 --- a/examples/platformer/main.rs +++ b/examples/platformer/main.rs @@ -26,18 +26,6 @@ fn main() { LdtkPlugin, RapierPhysicsPlugin::::pixels_per_meter(100.0), )) - .insert_resource(RapierConfiguration { - gravity: Vec2::new(0.0, -2000.0), - physics_pipeline_active: true, - query_pipeline_active: true, - timestep_mode: TimestepMode::Variable { - max_dt: 1.0 / 60.0, - time_scale: 1.0, - substeps: 1, - }, - scaled_shape_subdivision: 10, - force_update_from_transform_changes: false, - }) .insert_resource(LevelSelection::Uid(0)) .insert_resource(LdtkSettings { level_spawn_behavior: LevelSpawnBehavior::UseWorldTranslation { diff --git a/examples/platformer/misc_objects.rs b/examples/platformer/misc_objects.rs index c6263a98..39a12912 100644 --- a/examples/platformer/misc_objects.rs +++ b/examples/platformer/misc_objects.rs @@ -5,16 +5,16 @@ use crate::colliders::ColliderBundle; #[derive(Clone, Default, Bundle, LdtkEntity)] pub struct ChestBundle { - #[sprite_sheet_bundle] - pub sprite_sheet_bundle: LdtkSpriteSheetBundle, + #[sprite_sheet] + pub sprite_sheet: Sprite, #[from_entity_instance] pub collider_bundle: ColliderBundle, } #[derive(Clone, Default, Bundle, LdtkEntity)] pub struct PumpkinsBundle { - #[sprite_sheet_bundle(no_grid)] - pub sprite_sheet_bundle: LdtkSpriteSheetBundle, + #[sprite_sheet(no_grid)] + pub sprite_sheet: Sprite, } pub struct MiscObjectsPlugin; diff --git a/examples/platformer/player.rs b/examples/platformer/player.rs index 527736b5..ece3d50b 100644 --- a/examples/platformer/player.rs +++ b/examples/platformer/player.rs @@ -10,8 +10,8 @@ pub struct Player; #[derive(Clone, Default, Bundle, LdtkEntity)] pub struct PlayerBundle { - #[sprite_bundle("player.png")] - pub sprite_bundle: SpriteBundle, + #[sprite("player.png")] + pub sprite: Sprite, #[from_entity_instance] pub collider_bundle: ColliderBundle, pub player: Player, diff --git a/examples/platformer/walls.rs b/examples/platformer/walls.rs index 6f0bc570..3f1b8b83 100644 --- a/examples/platformer/walls.rs +++ b/examples/platformer/walls.rs @@ -34,7 +34,7 @@ pub fn spawn_wall_collision( wall_query: Query<(&GridCoords, &Parent), Added>, parent_query: Query<&Parent, Without>, level_query: Query<(Entity, &LevelIid)>, - ldtk_projects: Query<&Handle>, + ldtk_projects: Query<&LdtkProjectHandle>, ldtk_project_assets: Res>, ) { /// Represents a wide wall that is 1 tile tall diff --git a/examples/tile_based_game.rs b/examples/tile_based_game.rs index df2affc8..7afd6098 100644 --- a/examples/tile_based_game.rs +++ b/examples/tile_based_game.rs @@ -27,14 +27,17 @@ fn main() { } fn setup(mut commands: Commands, asset_server: Res) { - let mut camera = Camera2dBundle::default(); - camera.projection.scale = 0.5; - camera.transform.translation.x += 1280.0 / 4.0; - camera.transform.translation.y += 720.0 / 4.0; - commands.spawn(camera); + commands.spawn(( + Camera2d, + OrthographicProjection { + scale: 0.5, + ..OrthographicProjection::default_2d() + }, + Transform::from_xyz(1280.0 / 4.0, 720.0 / 4.0, 0.0), + )); commands.spawn(LdtkWorldBundle { - ldtk_handle: asset_server.load("tile-based-game.ldtk"), + ldtk_handle: asset_server.load("tile-based-game.ldtk").into(), ..Default::default() }); } @@ -45,8 +48,8 @@ struct Player; #[derive(Default, Bundle, LdtkEntity)] struct PlayerBundle { player: Player, - #[sprite_sheet_bundle] - sprite_bundle: LdtkSpriteSheetBundle, + #[sprite_sheet] + sprite_sheet: Sprite, #[grid_coords] grid_coords: GridCoords, } @@ -57,8 +60,8 @@ struct Goal; #[derive(Default, Bundle, LdtkEntity)] struct GoalBundle { goal: Goal, - #[sprite_sheet_bundle] - sprite_bundle: LdtkSpriteSheetBundle, + #[sprite_sheet] + sprite_sheet: Sprite, #[grid_coords] grid_coords: GridCoords, } @@ -129,7 +132,7 @@ fn cache_wall_locations( mut level_walls: ResMut, mut level_events: EventReader, walls: Query<&GridCoords, With>, - ldtk_project_entities: Query<&Handle>, + ldtk_project_entities: Query<&LdtkProjectHandle>, ldtk_project_assets: Res>, ) { for level_event in level_events.read() { diff --git a/examples/traitless.rs b/examples/traitless.rs index 94bf14f5..41168cfd 100644 --- a/examples/traitless.rs +++ b/examples/traitless.rs @@ -15,20 +15,14 @@ fn main() { } fn setup(mut commands: Commands, asset_server: Res) { - commands.spawn(Camera2dBundle::default()); + commands.spawn(Camera2d); commands.spawn(LdtkWorldBundle { - ldtk_handle: asset_server.load("my_project.ldtk"), + ldtk_handle: asset_server.load("my_project.ldtk").into(), ..Default::default() }); } -#[derive(Default, Component)] -struct ComponentA; - -#[derive(Default, Component)] -struct ComponentB; - fn process_my_entity( mut commands: Commands, entity_query: Query<(Entity, &Transform, &EntityInstance), Added>, @@ -53,14 +47,9 @@ fn process_my_entity( layout, }; - commands.entity(entity).insert(LdtkSpriteSheetBundle { - sprite_bundle: SpriteBundle { - texture, - transform: *transform, - ..Default::default() - }, - texture_atlas: atlas, - }); + commands + .entity(entity) + .insert((Sprite::from_atlas_image(texture, atlas), *transform)); } } } diff --git a/macros/src/ldtk_entity.rs b/macros/src/ldtk_entity.rs index 358c5d69..de7b4e7a 100644 --- a/macros/src/ldtk_entity.rs +++ b/macros/src/ldtk_entity.rs @@ -1,7 +1,7 @@ use quote::quote; -static SPRITE_BUNDLE_ATTRIBUTE_NAME: &str = "sprite_bundle"; -static SPRITE_SHEET_BUNDLE_ATTRIBUTE_NAME: &str = "sprite_sheet_bundle"; +static SPRITE_ATTRIBUTE_NAME: &str = "sprite"; +static SPRITE_SHEET_ATTRIBUTE_NAME: &str = "sprite_sheet"; static WORLDLY_ATTRIBUTE_NAME: &str = "worldly"; static GRID_COORDS_ATTRIBUTE_NAME: &str = "grid_coords"; static LDTK_ENTITY_ATTRIBUTE_NAME: &str = "ldtk_entity"; @@ -25,23 +25,21 @@ pub fn expand_ldtk_entity_derive(ast: syn::DeriveInput) -> proc_macro::TokenStre let field_name = field.ident.as_ref().unwrap(); let field_type = &field.ty; - let sprite_bundle = field + let sprite = field .attrs .iter() - .find(|a| *a.path.get_ident().as_ref().unwrap() == SPRITE_BUNDLE_ATTRIBUTE_NAME); - if let Some(attribute) = sprite_bundle { - field_constructions.push(expand_sprite_bundle_attribute( - attribute, field_name, field_type, - )); + .find(|a| *a.path.get_ident().as_ref().unwrap() == SPRITE_ATTRIBUTE_NAME); + if let Some(attribute) = sprite { + field_constructions.push(expand_sprite_attribute(attribute, field_name, field_type)); continue; } - let sprite_sheet_bundle = field + let sprite_sheet = field .attrs .iter() - .find(|a| *a.path.get_ident().as_ref().unwrap() == SPRITE_SHEET_BUNDLE_ATTRIBUTE_NAME); - if let Some(attribute) = sprite_sheet_bundle { - field_constructions.push(expand_sprite_sheet_bundle_attribute( + .find(|a| *a.path.get_ident().as_ref().unwrap() == SPRITE_SHEET_ATTRIBUTE_NAME); + if let Some(attribute) = sprite_sheet { + field_constructions.push(expand_sprite_sheet_attribute( attribute, field_name, field_type, )); continue; @@ -137,26 +135,29 @@ pub fn expand_ldtk_entity_derive(ast: syn::DeriveInput) -> proc_macro::TokenStre gen.into() } -fn expand_sprite_bundle_attribute( +fn expand_sprite_attribute( attribute: &syn::Attribute, field_name: &syn::Ident, field_type: &syn::Type, ) -> proc_macro2::TokenStream { // check the type match field_type { - syn::Type::Path(syn::TypePath { path: syn::Path { segments, .. }, .. }) => { + syn::Type::Path(syn::TypePath { + path: syn::Path { segments, .. }, + .. + }) => { if let Some(last) = segments.last() { - if last.ident != *"SpriteBundle" { - panic!("#[sprite_bundle...] attribute should apply to a field of type bevy::prelude::SpriteBundle") + if last.ident != *"Sprite" { + panic!("#[sprite...] attribute should apply to a field of type bevy::prelude::Sprite") } } - }, - _ => panic!("#[sprite_bundle...] attribute should apply to a field of type bevy::prelude::SpriteBundle") + } + _ => panic!("#[sprite...] attribute should apply to a field of type bevy::prelude::Sprite"), } match attribute .parse_meta() - .expect("Cannot parse #[sprite_bundle...] attribute") + .expect("Cannot parse #[sprite...] attribute") { syn::Meta::List(syn::MetaList { nested, .. }) if nested.len() == 1 => { match nested.first().unwrap() { @@ -164,88 +165,88 @@ fn expand_sprite_bundle_attribute( let asset_path = &asset.value(); quote! { - #field_name: bevy::prelude::SpriteBundle { - texture: asset_server.load(#asset_path), - ..Default::default() - }, + #field_name: bevy::prelude::Sprite::from_image( + asset_server.load(#asset_path)), } }, - _ => panic!("Expected asset path as the only argument of #[sprite_bundle(...)]"), + _ => panic!("Expected asset path as the only argument of #[sprite(...)]"), } }, syn::Meta::Path(_) => { quote! { - #field_name: bevy_ecs_ldtk::utils::sprite_bundle_from_entity_info(tileset), + #field_name: bevy_ecs_ldtk::utils::sprite_from_entity_info(tileset), } }, - _ => panic!("#[sprite_bundle...] attribute should take the form #[sprite_bundle(\"asset/path.png\")] or #[sprite_bundle]"), + _ => panic!("#[sprite...] attribute should take the form #[sprite(\"asset/path.png\")] or #[sprite]"), } } -fn expand_sprite_sheet_bundle_attribute( +fn expand_sprite_sheet_attribute( attribute: &syn::Attribute, field_name: &syn::Ident, field_type: &syn::Type, ) -> proc_macro2::TokenStream { // check the type match field_type { - syn::Type::Path(syn::TypePath { path: syn::Path { segments, .. }, .. }) => { + syn::Type::Path(syn::TypePath { + path: syn::Path { segments, .. }, + .. + }) => { if let Some(last) = segments.last() { - if last.ident != *"LdtkSpriteSheetBundle" { - panic!("#[sprite_sheet_bundle...] attribute should apply to a field of type bevy_ecs_ldtk::prelude::LdtkSpriteSheetBundle") + if last.ident != *"Sprite" { + panic!("#[sprite_sheet...] attribute should apply to a field of type bevy::prelude::Sprite") } } - }, - _ => panic!("#[sprite_sheet_bundle...] attribute should apply to a field of type bevy_ecs_ldtk::prelude::LdtkSpriteSheetBundle") + } + _ => panic!( + "#[sprite_sheet...] attribute should apply to a field of type bevy::prelude::Sprite" + ), } match attribute .parse_meta() - .expect("Cannot parse #[sprite_sheet_bundle...] attribute") + .expect("Cannot parse #[sprite_sheet...] attribute") { syn::Meta::List(syn::MetaList { nested, .. }) if nested.len() == 8 => { let mut nested_iter = nested.iter(); let asset_path = &match nested_iter.next() { Some(syn::NestedMeta::Lit(syn::Lit::Str(asset))) => asset.value(), - _ => panic!("First argument of #[sprite_sheet_bundle(...)] should be a string") + _ => panic!("First argument of #[sprite_sheet(...)] should be a string") }; let tile_width = match nested_iter.next() { Some(syn::NestedMeta::Lit(syn::Lit::Int(asset))) => asset.base10_parse::().unwrap(), - _ => panic!("Second argument of #[sprite_sheet_bundle(...)] should be an int") + _ => panic!("Second argument of #[sprite_sheet(...)] should be an int") }; let tile_height = match nested_iter.next() { Some(syn::NestedMeta::Lit(syn::Lit::Int(asset))) => asset.base10_parse::().unwrap(), - _ => panic!("Third argument of #[sprite_sheet_bundle(...)] should be an int") + _ => panic!("Third argument of #[sprite_sheet(...)] should be an int") }; let columns = match nested_iter.next() { Some(syn::NestedMeta::Lit(syn::Lit::Int(asset))) => asset.base10_parse::().unwrap(), - _ => panic!("Fourth argument of #[sprite_sheet_bundle(...)] should be an int") + _ => panic!("Fourth argument of #[sprite_sheet(...)] should be an int") }; let rows = match nested_iter.next() { Some(syn::NestedMeta::Lit(syn::Lit::Int(asset))) => asset.base10_parse::().unwrap(), - _ => panic!("Fifth argument of #[sprite_sheet_bundle(...)] should be an int") + _ => panic!("Fifth argument of #[sprite_sheet(...)] should be an int") }; let padding = match nested_iter.next() { Some(syn::NestedMeta::Lit(syn::Lit::Int(asset))) => asset.base10_parse::().unwrap(), - _ => panic!("Sixth argument of #[sprite_sheet_bundle(...)] should be an int") + _ => panic!("Sixth argument of #[sprite_sheet(...)] should be an int") }; let offset = match nested_iter.next() { Some(syn::NestedMeta::Lit(syn::Lit::Int(asset))) => asset.base10_parse::().unwrap(), - _ => panic!("Seventh argument of #[sprite_sheet_bundle(...)] should be an int") + _ => panic!("Seventh argument of #[sprite_sheet(...)] should be an int") }; let index = match nested_iter.next() { Some(syn::NestedMeta::Lit(syn::Lit::Int(asset))) => asset.base10_parse::().unwrap(), - _ => panic!("Eighth argument of #[sprite_sheet_bundle(...)] should be an int") + _ => panic!("Eighth argument of #[sprite_sheet(...)] should be an int") }; quote! { - #field_name: LdtkSpriteSheetBundle{ - sprite_bundle: bevy::prelude::SpriteBundle { - texture: asset_server.load(#asset_path).into(), - ..Default::default() - }, - texture_atlas: bevy::prelude::TextureAtlas { + #field_name: bevy::prelude::Sprite::from_atlas_image( + asset_server.load(#asset_path), + bevy::prelude::TextureAtlas { layout: texture_atlases.add( bevy::prelude::TextureAtlasLayout::from_grid( bevy::prelude::UVec2::new(#tile_width, #tile_height), @@ -253,8 +254,8 @@ fn expand_sprite_sheet_bundle_attribute( Some(bevy::prelude::UVec2::splat(#offset)), )), index: #index - } - }, + }, + ), } }, syn::Meta::List(syn::MetaList { nested, .. }) if nested.len() == 1 => { @@ -262,19 +263,19 @@ fn expand_sprite_sheet_bundle_attribute( match nested_iter.next() { Some(syn::NestedMeta::Meta(syn::Meta::Path(path))) if path.is_ident("no_grid") => {}, - _ => panic!("Argument of #[sprite_sheet_bundle(...)] should be no_grid") + _ => panic!("Argument of #[sprite_sheet(...)] should be no_grid") }; quote! { - #field_name: bevy_ecs_ldtk::utils::sprite_sheet_bundle_from_entity_info(entity_instance, tileset, tileset_definition, texture_atlases, false), + #field_name: bevy_ecs_ldtk::utils::sprite_sheet_from_entity_info(entity_instance, tileset, tileset_definition, texture_atlases, false), } }, syn::Meta::Path(_) => { quote! { - #field_name: bevy_ecs_ldtk::utils::sprite_sheet_bundle_from_entity_info(entity_instance, tileset, tileset_definition, texture_atlases, true), + #field_name: bevy_ecs_ldtk::utils::sprite_sheet_from_entity_info(entity_instance, tileset, tileset_definition, texture_atlases, true), } }, - _ => panic!("#[sprite_sheet_bundle...] attribute should take the form #[sprite_sheet_bundle(\"asset/path.png\", tile_width, tile_height, columns, rows, padding, offset, index)], #[sprite_sheet_bundle(no_grid)] or #[sprite_sheet_bundle]"), + _ => panic!("#[sprite_sheet...] attribute should take the form #[sprite_sheet(\"asset/path.png\", tile_width, tile_height, columns, rows, padding, offset, index)], #[sprite_sheet(no_grid)] or #[sprite_sheet]"), } } diff --git a/macros/src/lib.rs b/macros/src/lib.rs index 5604c614..ef1ce845 100644 --- a/macros/src/lib.rs +++ b/macros/src/lib.rs @@ -6,8 +6,8 @@ mod ldtk_int_cell; #[proc_macro_derive( LdtkEntity, attributes( - sprite_bundle, - sprite_sheet_bundle, + sprite, + sprite_sheet, worldly, grid_coords, ldtk_entity, diff --git a/src/app/ldtk_entity.rs b/src/app/ldtk_entity.rs index dbaa705a..9f780a99 100644 --- a/src/app/ldtk_entity.rs +++ b/src/app/ldtk_entity.rs @@ -10,8 +10,7 @@ use std::{collections::HashMap, marker::PhantomData}; /// [Bundle]: bevy::prelude::Bundle /// [App]: bevy::prelude::App /// [Component]: bevy::prelude::Component -/// [SpriteBundle]: bevy::prelude::SpriteBundle -/// [LdtkSpriteSheetBundle]: crate::prelude::LdtkSpriteSheetBundle +/// [Sprite]: bevy::prelude::Sprite /// [TextureAtlasLayout]: bevy::prelude::TextureAtlasLayout /// /// Provides a constructor which can be used for spawning entities from an LDtk file. @@ -65,14 +64,14 @@ use std::{collections::HashMap, marker::PhantomData}; /// is required (unless all fields are overriden, see below). /// However, this behavior can be overridden with some field attribute macros... /// -/// ### `#[sprite_bundle...]` -/// Indicates that a [SpriteBundle] field should be created with an actual material/image. +/// ### `#[sprite...]` +/// Indicates that a [Sprite] field should be created with an actual material/image. /// There are two forms for this attribute: -/// - `#[sprite_bundle("path/to/asset.png")]` will create the field using the image at the provided +/// - `#[sprite("path/to/asset.png")]` will create the field using the image at the provided /// path in the assets folder. -/// - `#[sprite_bundle]` will create the field using its Editor Visual image in LDtk, if it has one. +/// - `#[sprite]` will create the field using its Editor Visual image in LDtk, if it has one. /// -/// Note that if your editor visual is part of a tilemap, you should use `#[sprite_sheet_bundle]` instead. +/// Note that if your editor visual is part of a tilemap, you should use `#[sprite_sheet]` instead. /// ``` /// # use bevy::prelude::*; /// # use bevy_ecs_ldtk::prelude::*; @@ -84,8 +83,8 @@ use std::{collections::HashMap, marker::PhantomData}; /// # struct Health; /// #[derive(Bundle, LdtkEntity, Default)] /// pub struct Gem { -/// #[sprite_bundle("textures/gem.png")] -/// sprite_bundle: SpriteBundle, +/// #[sprite("textures/gem.png")] +/// sprite: Sprite, /// sellable: Sellable, /// } /// @@ -93,21 +92,21 @@ use std::{collections::HashMap, marker::PhantomData}; /// pub struct Player { /// player: PlayerComponent, /// health: Health, -/// #[sprite_bundle] // Uses the Editor Visual sprite in LDtk -/// sprite_bundle: SpriteBundle, +/// #[sprite] // Uses the Editor Visual sprite in LDtk +/// sprite: Sprite, /// } /// ``` /// -/// ### `#[sprite_sheet_bundle...]` -/// Similar to `#[sprite_bundle...]`, indicates that a [LdtkSpriteSheetBundle] field should be created +/// ### `#[sprite_sheet...]` +/// Similar to `#[sprite...]`, indicates that a [Sprite] field should be created /// with an actual material/image. /// There are two forms for this attribute: -/// - `#[sprite_sheet_bundle("path/to/asset.png", tile_width, tile_height, columns, rows, padding, +/// - `#[sprite_sheet("path/to/asset.png", tile_width, tile_height, columns, rows, padding, /// offset, index)]` will create the field using all of the information provided. /// Similar to using [TextureAtlasLayout::from_grid()]. -/// - `#[sprite_sheet_bundle]` will create the field using information from the LDtk Editor visual, +/// - `#[sprite_sheet]` will create the field using information from the LDtk Editor visual, /// if it has one. -/// - `#[sprite_sheet_bundle(no_grid)]` will create the field using information from the LDtk +/// - `#[sprite_sheet(no_grid)]` will create the field using information from the LDtk /// Editor visual, if it has one, but without using a grid. Instead a single texture will be used. /// This may be useful if the LDtk entity's visual uses a rectangle of tiles from its tileset, /// but will prevent using the generated [TextureAtlasLayout] for animation purposes. @@ -120,8 +119,8 @@ use std::{collections::HashMap, marker::PhantomData}; /// # struct BleedDamage; /// #[derive(Bundle, LdtkEntity, Default)] /// pub struct Sword { -/// #[sprite_sheet_bundle("weapons.png", 32, 32, 4, 5, 5, 1, 17)] -/// sprite_sheet: LdtkSpriteSheetBundle, +/// #[sprite_sheet("weapons.png", 32, 32, 4, 5, 5, 1, 17)] +/// sprite_sheet: Sprite, /// damage: Damage, /// } /// @@ -129,8 +128,8 @@ use std::{collections::HashMap, marker::PhantomData}; /// pub struct Dagger { /// damage: Damage, /// bleed_damage: BleedDamage, -/// #[sprite_sheet_bundle] -/// sprite_sheet: LdtkSpriteSheetBundle, +/// #[sprite_sheet] +/// sprite_sheet: Sprite, /// } /// ``` /// @@ -152,8 +151,8 @@ use std::{collections::HashMap, marker::PhantomData}; /// #[derive(Bundle, LdtkEntity, Default)] /// pub struct PlayerBundle { /// player: Player, -/// #[sprite_sheet_bundle] -/// sprite_sheet_bundle: LdtkSpriteSheetBundle, +/// #[sprite_sheet] +/// sprite_sheet: Sprite, /// #[worldly] /// worldly: Worldly, /// } @@ -175,8 +174,8 @@ use std::{collections::HashMap, marker::PhantomData}; /// pub struct BlockBundle { /// block: Block, /// movable: Movable, -/// #[sprite_sheet_bundle] -/// sprite_sheet_bundle: LdtkSpriteSheetBundle, +/// #[sprite_sheet] +/// sprite_sheet: Sprite, /// #[grid_coords] /// grid_coords: GridCoords, /// } @@ -199,8 +198,8 @@ use std::{collections::HashMap, marker::PhantomData}; /// #[derive(Bundle, LdtkEntity, Default)] /// pub struct Weapon { /// damage: Damage, -/// #[sprite_bundle] -/// sprite: SpriteBundle, +/// #[sprite] +/// sprite: Sprite, /// } /// /// #[derive(Bundle, LdtkEntity, Default)] @@ -240,8 +239,8 @@ use std::{collections::HashMap, marker::PhantomData}; /// /// #[derive(Bundle, LdtkEntity, Default)] /// pub struct NickelBundle { -/// #[sprite_bundle] -/// sprite: SpriteBundle, +/// #[sprite] +/// sprite: Sprite, /// #[from_entity_instance] /// sellable: Sellable, /// #[from_entity_instance] @@ -348,7 +347,7 @@ impl LdtkEntity for EntityInstanceBundle { } } -impl LdtkEntity for SpriteBundle { +impl LdtkEntity for Sprite { fn bundle_entity( _: &EntityInstance, _: &LayerInstance, @@ -357,7 +356,7 @@ impl LdtkEntity for SpriteBundle { _: &AssetServer, _: &mut Assets, ) -> Self { - utils::sprite_bundle_from_entity_info(tileset) + utils::sprite_from_entity_info(tileset) } } diff --git a/src/assets/ldtk_external_level.rs b/src/assets/ldtk_external_level.rs index c70a27bd..5d48df59 100644 --- a/src/assets/ldtk_external_level.rs +++ b/src/assets/ldtk_external_level.rs @@ -2,9 +2,8 @@ use std::io; use crate::ldtk::{loaded_level::LoadedLevel, Level}; use bevy::{ - asset::{io::Reader, AssetLoader, AsyncReadExt, LoadContext}, + asset::{io::Reader, AssetLoader, LoadContext}, prelude::*, - utils::ConditionalSendFuture, }; use thiserror::Error; @@ -61,27 +60,23 @@ impl AssetLoader for LdtkExternalLevelLoader { type Settings = (); type Error = LdtkExternalLevelLoaderError; - fn load<'a>( - &'a self, - reader: &'a mut Reader, - _settings: &'a Self::Settings, - _load_context: &'a mut LoadContext, - ) -> impl ConditionalSendFuture< - Output = Result<::Asset, ::Error>, - > { - Box::pin(async move { - let mut bytes = Vec::new(); - reader.read_to_end(&mut bytes).await?; - let data: Level = serde_json::from_slice(&bytes)?; - - if data.layer_instances.is_none() { - Err(LdtkExternalLevelLoaderError::NullLayers)?; - } - - let ldtk_level = LdtkExternalLevel { data }; - - Ok(ldtk_level) - }) + async fn load( + &self, + reader: &mut dyn Reader, + _settings: &Self::Settings, + _load_context: &mut LoadContext<'_>, + ) -> Result { + let mut bytes = Vec::new(); + reader.read_to_end(&mut bytes).await?; + let data: Level = serde_json::from_slice(&bytes)?; + + if data.layer_instances.is_none() { + Err(LdtkExternalLevelLoaderError::NullLayers)?; + } + + let ldtk_level = LdtkExternalLevel { data }; + + Ok(ldtk_level) } fn extensions(&self) -> &[&str] { diff --git a/src/assets/ldtk_project.rs b/src/assets/ldtk_project.rs index 88f3c308..b883d2d8 100644 --- a/src/assets/ldtk_project.rs +++ b/src/assets/ldtk_project.rs @@ -7,10 +7,9 @@ use crate::{ ldtk::{raw_level_accessor::RawLevelAccessor, LdtkJson, Level}, }; use bevy::{ - asset::{io::Reader, AssetLoader, AssetPath, AsyncReadExt, LoadContext}, + asset::{io::Reader, AssetLoader, AssetPath, LoadContext}, prelude::*, reflect::Reflect, - utils::ConditionalSendFuture, }; use derive_getters::Getters; use derive_more::From; @@ -225,88 +224,84 @@ impl AssetLoader for LdtkProjectLoader { type Settings = (); type Error = LdtkProjectLoaderError; - fn load<'a>( - &'a self, - reader: &'a mut Reader, - _settings: &'a Self::Settings, - load_context: &'a mut LoadContext, - ) -> impl ConditionalSendFuture< - Output = Result<::Asset, ::Error>, - > { - Box::pin(async move { - let mut bytes = Vec::new(); - reader.read_to_end(&mut bytes).await?; - let data: LdtkJson = serde_json::from_slice(&bytes)?; - - let mut tileset_map: HashMap> = HashMap::new(); - for tileset in &data.defs.tilesets { - if let Some(tileset_path) = &tileset.rel_path { - let asset_path = ldtk_path_to_asset_path(load_context.path(), tileset_path); - - tileset_map.insert(tileset.uid, load_context.load(asset_path)); - } else if tileset.embed_atlas.is_some() { - warn!("Ignoring LDtk's Internal_Icons. They cannot be displayed due to their license."); - } else { - let identifier = &tileset.identifier; - warn!("{identifier} tileset cannot be loaded, it has a null relative path."); - } + async fn load( + &self, + reader: &mut dyn Reader, + _settings: &Self::Settings, + load_context: &mut LoadContext<'_>, + ) -> Result { + let mut bytes = Vec::new(); + reader.read_to_end(&mut bytes).await?; + let data: LdtkJson = serde_json::from_slice(&bytes)?; + + let mut tileset_map: HashMap> = HashMap::new(); + for tileset in &data.defs.tilesets { + if let Some(tileset_path) = &tileset.rel_path { + let asset_path = ldtk_path_to_asset_path(load_context.path(), tileset_path); + + tileset_map.insert(tileset.uid, load_context.load(asset_path)); + } else if tileset.embed_atlas.is_some() { + warn!("Ignoring LDtk's Internal_Icons. They cannot be displayed due to their license."); + } else { + let identifier = &tileset.identifier; + warn!("{identifier} tileset cannot be loaded, it has a null relative path."); } + } - let int_grid_image_handle = data - .defs - .create_int_grid_image() - .map(|image| load_context.add_labeled_asset("int_grid_image".to_string(), image)); - - let ldtk_project = if data.external_levels { - #[cfg(feature = "external_levels")] - { - let mut level_map = HashMap::new(); - - for (level_indices, level) in data.iter_raw_levels_with_indices() { - let level_metadata = - load_external_level_metadata(load_context, level_indices, level)?; - - level_map.insert(level.iid.clone(), level_metadata); - } - - LdtkProject::new( - LdtkProjectData::Parent(LdtkJsonWithMetadata::new(data, level_map)), - tileset_map, - int_grid_image_handle, - ) - } + let int_grid_image_handle = data + .defs + .create_int_grid_image() + .map(|image| load_context.add_labeled_asset("int_grid_image".to_string(), image)); - #[cfg(not(feature = "external_levels"))] - { - Err(LdtkProjectLoaderError::ExternalLevelsDisabled)? - } - } else { - #[cfg(feature = "internal_levels")] - { - let mut level_map = HashMap::new(); - - for (level_indices, level) in data.iter_raw_levels_with_indices() { - let level_metadata = - load_level_metadata(load_context, level_indices, level, true)?; - - level_map.insert(level.iid.clone(), level_metadata); - } - - LdtkProject::new( - LdtkProjectData::Standalone(LdtkJsonWithMetadata::new(data, level_map)), - tileset_map, - int_grid_image_handle, - ) + let ldtk_project = if data.external_levels { + #[cfg(feature = "external_levels")] + { + let mut level_map = HashMap::new(); + + for (level_indices, level) in data.iter_raw_levels_with_indices() { + let level_metadata = + load_external_level_metadata(load_context, level_indices, level)?; + + level_map.insert(level.iid.clone(), level_metadata); } - #[cfg(not(feature = "internal_levels"))] - { - Err(LdtkProjectLoaderError::InternalLevelsDisabled)? + LdtkProject::new( + LdtkProjectData::Parent(LdtkJsonWithMetadata::new(data, level_map)), + tileset_map, + int_grid_image_handle, + ) + } + + #[cfg(not(feature = "external_levels"))] + { + Err(LdtkProjectLoaderError::ExternalLevelsDisabled)? + } + } else { + #[cfg(feature = "internal_levels")] + { + let mut level_map = HashMap::new(); + + for (level_indices, level) in data.iter_raw_levels_with_indices() { + let level_metadata = + load_level_metadata(load_context, level_indices, level, true)?; + + level_map.insert(level.iid.clone(), level_metadata); } - }; - Ok(ldtk_project) - }) + LdtkProject::new( + LdtkProjectData::Standalone(LdtkJsonWithMetadata::new(data, level_map)), + tileset_map, + int_grid_image_handle, + ) + } + + #[cfg(not(feature = "internal_levels"))] + { + Err(LdtkProjectLoaderError::InternalLevelsDisabled)? + } + }; + + Ok(ldtk_project) } fn extensions(&self) -> &[&str] { diff --git a/src/components/ldtk_sprite_sheet_bundle.rs b/src/components/ldtk_sprite_sheet_bundle.rs deleted file mode 100644 index de14987d..00000000 --- a/src/components/ldtk_sprite_sheet_bundle.rs +++ /dev/null @@ -1,43 +0,0 @@ -use bevy::{ - asset::{AssetServer, Assets, Handle}, - prelude::Bundle, - render::texture::Image, - sprite::{SpriteBundle, TextureAtlas, TextureAtlasLayout}, -}; - -use crate::{ - prelude::{LayerInstance, LdtkEntity, TilesetDefinition}, - utils, EntityInstance, -}; - -/// [`Bundle`] for sprite-sheet-based sprites, similar to bevy 0.13's `SpriteSheetBundle`. -/// -/// Implements [`LdtkEntity`], and can be added to an [`LdtkEntity`] bundle with the `#[sprite_sheet_bundle]` -/// field attribute. -/// See [`LdtkEntity#sprite_sheet_bundle`] for attribute macro usage. -/// -/// [`Bundle`]: https://docs.rs/bevy/latest/bevy/ecs/prelude/trait.Bundle.html -#[derive(Bundle, Clone, Debug, Default)] -pub struct LdtkSpriteSheetBundle { - pub sprite_bundle: SpriteBundle, - pub texture_atlas: TextureAtlas, -} - -impl LdtkEntity for LdtkSpriteSheetBundle { - fn bundle_entity( - entity_instance: &EntityInstance, - _: &LayerInstance, - tileset: Option<&Handle>, - tileset_definition: Option<&TilesetDefinition>, - _: &AssetServer, - texture_atlases: &mut Assets, - ) -> Self { - utils::sprite_sheet_bundle_from_entity_info( - entity_instance, - tileset, - tileset_definition, - texture_atlases, - true, - ) - } -} diff --git a/src/components/mod.rs b/src/components/mod.rs index 17829213..36513297 100644 --- a/src/components/mod.rs +++ b/src/components/mod.rs @@ -8,15 +8,13 @@ pub use level_iid::LevelIid; mod level_set; pub use level_set::LevelSet; -mod ldtk_sprite_sheet_bundle; -pub use ldtk_sprite_sheet_bundle::LdtkSpriteSheetBundle; - pub use crate::ldtk::EntityInstance; use crate::{ ldtk::{LayerInstance, Type}, prelude::LdtkProject, utils::ldtk_grid_coords_to_grid_coords, }; +use bevy::asset::UntypedAssetId; use bevy::prelude::*; use std::ops::{Add, AddAssign, Mul, MulAssign, Sub, SubAssign}; @@ -311,7 +309,7 @@ impl From<&LayerInstance> for LayerMetadata { #[reflect(Component)] pub struct Respawn; -#[derive(Copy, Clone, Debug, Default, Bundle)] +#[derive(Clone, Debug, Default, Bundle)] pub(crate) struct TileGridBundle { pub tile_bundle: TileBundle, pub grid_coords: GridCoords, @@ -327,6 +325,47 @@ pub(crate) struct EntityInstanceBundle { pub entity_instance: EntityInstance, } +/// `Component` storing the LDtk project asset handle, marking the root entity for the plugin to spawn levels in. +/// +/// For a more detailed explanation of the spawning process, please see the +/// [*Anatomy of the World*](https://trouv.github.io/bevy_ecs_ldtk/v0.10.0/explanation/anatomy-of-the-world.html) +/// chapter of the `bevy_ecs_ldtk` book. +#[derive(Debug, Default, Clone, Component, Reflect, Deref, DerefMut)] +#[reflect(Component)] +pub struct LdtkProjectHandle { + pub handle: Handle, +} + +impl From> for LdtkProjectHandle { + fn from(handle: Handle) -> Self { + LdtkProjectHandle { handle } + } +} + +impl From<&LdtkProjectHandle> for AssetId { + fn from(val: &LdtkProjectHandle) -> Self { + val.id() + } +} + +impl From for AssetId { + fn from(val: LdtkProjectHandle) -> Self { + val.id() + } +} + +impl From<&LdtkProjectHandle> for UntypedAssetId { + fn from(val: &LdtkProjectHandle) -> Self { + val.id().into() + } +} + +impl From for UntypedAssetId { + fn from(val: LdtkProjectHandle) -> Self { + val.id().into() + } +} + /// `Bundle` for spawning LDtk worlds and their levels. The main bundle for using this plugin. /// /// For a more detailed explanation of the resulting world, please see the @@ -334,7 +373,7 @@ pub(crate) struct EntityInstanceBundle { /// chapter of the `bevy_ecs_ldtk` book. #[derive(Clone, Default, Bundle)] pub struct LdtkWorldBundle { - pub ldtk_handle: Handle, + pub ldtk_handle: LdtkProjectHandle, pub level_set: LevelSet, pub transform: Transform, pub global_transform: GlobalTransform, diff --git a/src/ldtk/field_instance.rs b/src/ldtk/field_instance.rs index 24fe34b9..526f2517 100644 --- a/src/ldtk/field_instance.rs +++ b/src/ldtk/field_instance.rs @@ -189,7 +189,7 @@ impl<'de> Deserialize<'de> for FieldInstance { } #[derive(PartialEq, Debug, Clone, Serialize, Reflect)] -#[reflect_value()] +#[reflect(opaque)] #[serde(untagged)] /// The actual value of a field instance on a [Level] or [EntityInstance]. /// diff --git a/src/ldtk/loaded_level.rs b/src/ldtk/loaded_level.rs index 17615bc0..8d7207f1 100644 --- a/src/ldtk/loaded_level.rs +++ b/src/ldtk/loaded_level.rs @@ -39,7 +39,7 @@ impl<'a> TryFrom<&'a Level> for LoadedLevel<'a> { } } -impl<'a> LoadedLevel<'a> { +impl LoadedLevel<'_> { /// The raw level data borrowed by this instance. pub fn raw(&self) -> &Level { self.level @@ -170,7 +170,7 @@ impl<'a> LoadedLevel<'a> { } } -impl<'a> LdtkFields for LoadedLevel<'a> { +impl LdtkFields for LoadedLevel<'_> { fn field_instances(&self) -> &[FieldInstance] { self.level.field_instances() } diff --git a/src/level.rs b/src/level.rs index 4c1fd14d..3b9ab838 100644 --- a/src/level.rs +++ b/src/level.rs @@ -38,14 +38,14 @@ enum BackgroundImageError { ImageNotLoaded, } -fn background_image_sprite_sheet_bundle( +fn background_image_sprite_sheet( images: &Assets, texture_atlases: &mut Assets, background_image_handle: &Handle, background_position: &LevelBackgroundPosition, level_height: i32, transform_z: f32, -) -> Result { +) -> Result<(Sprite, Transform), BackgroundImageError> { if let Some(background_image) = images.get(background_image_handle) { // We need to use a texture atlas to apply the correct crop to the image let tile_size = UVec2::new( @@ -80,18 +80,17 @@ fn background_image_sprite_sheet_bundle( let center_translation = top_left_translation + (Vec2::new(scaled_size.x, -scaled_size.y) / 2.); - Ok(LdtkSpriteSheetBundle { - sprite_bundle: SpriteBundle { - texture: background_image_handle.clone(), - transform: Transform::from_translation(center_translation.extend(transform_z)) - .with_scale(scale.extend(1.)), - ..Default::default() - }, - texture_atlas: TextureAtlas { - index, - layout: texture_atlases.add(texture_atlas_layout), - }, - }) + Ok(( + Sprite::from_atlas_image( + background_image_handle.clone(), + TextureAtlas { + index, + layout: texture_atlases.add(texture_atlas_layout), + }, + ), + Transform::from_translation(center_translation.extend(transform_z)) + .with_scale(scale.extend(1.)), + )) } else { Err(BackgroundImageError::ImageNotLoaded) } @@ -133,12 +132,12 @@ fn insert_metadata_to_tile( metadata_inserted } -fn spatial_bundle_for_tiles(grid_coords: GridCoords, grid_size: i32) -> SpatialBundle { +fn spatial_bundle_for_tiles(grid_coords: GridCoords, grid_size: i32) -> Transform { let translation = grid_coords_to_translation_relative_to_tile_layer(grid_coords, IVec2::splat(grid_size)) .extend(0.); - SpatialBundle::from_transform(Transform::from_translation(translation)) + Transform::from_translation(translation) } fn insert_spatial_bundle_for_layer_tiles( @@ -234,15 +233,14 @@ pub fn spawn_level( let translation = Vec3::new(*level.px_wid() as f32, *level.px_hei() as f32, 0.) / 2.; let background_entity = commands - .spawn(SpriteBundle { - sprite: Sprite { + .spawn(( + Sprite { color: *level.bg_color(), custom_size: Some(Vec2::new(*level.px_wid() as f32, *level.px_hei() as f32)), ..default() }, - transform: Transform::from_translation(translation), - ..default() - }) + Transform::from_translation(translation), + )) .id(); commands.entity(ldtk_entity).add_child(background_entity); @@ -253,7 +251,7 @@ pub fn spawn_level( if let (Some(background_image_handle), Some(background_position)) = (background_image, level.bg_pos()) { - match background_image_sprite_sheet_bundle( + match background_image_sprite_sheet( images, texture_atlases, background_image_handle, @@ -261,9 +259,9 @@ pub fn spawn_level( *level.px_hei(), layer_z as f32, ) { - Ok(sprite_sheet_bundle) => { + Ok(sprite_sheet) => { commands.entity(ldtk_entity).with_children(|parent| { - parent.spawn(sprite_sheet_bundle); + parent.spawn(sprite_sheet); }); layer_z += 1; @@ -291,9 +289,10 @@ pub fn spawn_level( match layer_instance.layer_instance_type { Type::Entities => { let layer_entity = commands - .spawn(SpatialBundle::from_transform(Transform::from_translation( + .spawn(Transform::from_translation( layer_offset.extend(layer_z as f32), - ))) + )) + .insert(Visibility::default()) .insert(LayerMetadata::from(layer_instance)) .insert(Name::new(layer_instance.identifier.to_owned())) .with_children(|commands| { @@ -351,10 +350,7 @@ pub fn spawn_level( texture_atlases, ); - entity_commands.insert(SpatialBundle { - transform, - ..default() - }); + entity_commands.insert(transform); } } }) @@ -702,13 +698,14 @@ pub fn spawn_level( commands .entity(layer_entity) .insert(tilemap_bundle) - .insert(SpatialBundle::from_transform(Transform::from_translation( + .insert(Transform::from_translation( (bottom_left_pixel + centering_adjustment + pivot_adjustment + layer_offset) .extend(layer_z as f32), - ))) + )) + .insert(Visibility::default()) .insert(LayerMetadata::from(layer_instance)) .insert(Name::new(layer_instance.identifier.to_owned())); diff --git a/src/lib.rs b/src/lib.rs index 55975c92..55ef1880 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -59,10 +59,9 @@ pub mod prelude { pub use crate::{ app::{LdtkEntity, LdtkEntityAppExt, LdtkIntCell, LdtkIntCellAppExt}, assets::{LdtkProject, LevelIndices, LevelMetadataAccessor}, - components::LdtkSpriteSheetBundle, components::{ - EntityIid, EntityInstance, GridCoords, IntGridCell, LayerMetadata, LdtkWorldBundle, - LevelIid, LevelSet, Respawn, TileEnumTags, TileMetadata, Worldly, + EntityIid, EntityInstance, GridCoords, IntGridCell, LayerMetadata, LdtkProjectHandle, + LdtkWorldBundle, LevelIid, LevelSet, Respawn, TileEnumTags, TileMetadata, Worldly, }, ldtk::{ self, ldtk_fields::LdtkFields, raw_level_accessor::RawLevelAccessor, FieldValue, diff --git a/src/systems.rs b/src/systems.rs index d195b88c..fd99baf6 100644 --- a/src/systems.rs +++ b/src/systems.rs @@ -15,7 +15,7 @@ use crate::{ #[cfg(feature = "external_levels")] use crate::assets::LdtkExternalLevel; -use bevy::{asset::RecursiveDependencyLoadState, ecs::system::SystemState, prelude::*}; +use bevy::{ecs::system::SystemState, prelude::*}; use std::collections::{HashMap, HashSet}; /// Detects [LdtkProject] events and spawns levels as children of the [LdtkWorldBundle]. @@ -23,7 +23,7 @@ use std::collections::{HashMap, HashSet}; pub fn process_ldtk_assets( mut commands: Commands, mut ldtk_project_events: EventReader>, - ldtk_world_query: Query<(Entity, &Handle)>, + ldtk_world_query: Query<(Entity, &LdtkProjectHandle)>, #[cfg(feature = "render")] ldtk_settings: Res, #[cfg(feature = "render")] mut clear_color: ResMut, #[cfg(feature = "render")] ldtk_project_assets: Res>, @@ -73,7 +73,7 @@ pub fn apply_level_selection( level_selection: Option>, ldtk_settings: Res, ldtk_project_assets: Res>, - mut level_set_query: Query<(&Handle, &mut LevelSet)>, + mut level_set_query: Query<(&LdtkProjectHandle, &mut LevelSet)>, #[cfg(feature = "render")] mut clear_color: ResMut, ) { if let Some(level_selection) = level_selection { @@ -123,7 +123,7 @@ pub fn apply_level_set( Entity, &LevelSet, Option<&Children>, - &Handle, + &LdtkProjectHandle, Option<&Respawn>, )>, ldtk_level_query: Query<(&LevelIid, Entity)>, @@ -138,7 +138,7 @@ pub fn apply_level_set( if let Some(load_state) = asset_server.get_recursive_dependency_load_state(ldtk_asset_handle) { - if load_state != RecursiveDependencyLoadState::Loaded { + if !load_state.is_loaded() { continue; } } @@ -164,7 +164,7 @@ pub fn apply_level_set( }) .collect::>(); - commands.entity(world_entity).push_children(&spawned_levels); + commands.entity(world_entity).add_children(&spawned_levels); // Despawn levels that shouldn't be spawned but are for &iid in previous_iids.difference(&level_set_as_ref) { @@ -201,10 +201,8 @@ fn pre_spawn_level(commands: &mut Commands, level: &Level, ldtk_settings: &LdtkS commands .spawn(LevelIid::new(level.iid.clone())) - .insert(SpatialBundle { - transform: Transform::from_translation(translation), - ..default() - }) + .insert(Transform::from_translation(translation)) + .insert(Visibility::default()) .insert(Name::new(level.identifier.clone())) .id() } @@ -221,7 +219,7 @@ pub fn process_ldtk_levels( #[cfg(feature = "external_levels")] level_assets: Res>, ldtk_entity_map: NonSend, ldtk_int_cell_map: NonSend, - ldtk_query: Query<&Handle>, + ldtk_query: Query<&LdtkProjectHandle>, level_query: Query< ( Entity, @@ -336,7 +334,7 @@ pub fn process_ldtk_levels( pub fn clean_respawn_entities(world: &mut World) { #[allow(clippy::type_complexity)] let mut system_state: SystemState<( - Query<&Children, (With>, With)>, + Query<&Children, (With, With)>, Query<(Entity, &LevelIid), With>, Query<&LevelIid, Without>, Query>, diff --git a/src/utils.rs b/src/utils.rs index f2acda5f..c6f60e9b 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -6,10 +6,7 @@ use crate::{ components::{GridCoords, IntGridCell}, }; -use crate::{ - components::{LdtkSpriteSheetBundle, TileGridBundle}, - ldtk::*, -}; +use crate::{components::TileGridBundle, ldtk::*}; use bevy::prelude::*; use bevy_ecs_tilemap::{ map::{TilemapId, TilemapSize}, @@ -308,18 +305,18 @@ where try_each_optional_permutation(a, b, |x, y| map.get(&(x, y))).unwrap_or(default) } -/// Creates a [`LdtkSpriteSheetBundle`] from the entity information available to the +/// Creates a [`Sprite`] with [`TextureAtlas`] from the entity information available to the /// [LdtkEntity::bundle_entity] method. /// -/// Used for the `#[sprite_sheet_bundle]` attribute macro for `#[derive(LdtkEntity)]`. -/// See [LdtkEntity#sprite_sheet_bundle] for more info. -pub fn sprite_sheet_bundle_from_entity_info( +/// Used for the `#[sprite_sheet]` attribute macro for `#[derive(LdtkEntity)]`. +/// See [LdtkEntity#sprite_sheet] for more info. +pub fn sprite_sheet_from_entity_info( entity_instance: &EntityInstance, tileset: Option<&Handle>, tileset_definition: Option<&TilesetDefinition>, texture_atlases: &mut Assets, grid: bool, -) -> LdtkSpriteSheetBundle { +) -> Sprite { match (tileset, &entity_instance.tile, tileset_definition) { (Some(tileset), Some(tile), Some(tileset_definition)) => { let texture_atlas = if grid { @@ -355,39 +352,30 @@ pub fn sprite_sheet_bundle_from_entity_info( } }; - LdtkSpriteSheetBundle { - sprite_bundle: SpriteBundle { - texture: tileset.clone(), - ..Default::default() - }, - texture_atlas, - } + Sprite::from_atlas_image(tileset.clone(), texture_atlas) } _ => { - warn!("EntityInstance needs a tile, an associated tileset, and an associated tileset definition to be bundled as a LdtkSpriteSheetBundle"); - LdtkSpriteSheetBundle::default() + warn!("EntityInstance needs a tile, an associated tileset, and an associated tileset definition to be inserted as a Sprite"); + Sprite::default() } } } -/// Creates a [SpriteBundle] from the entity information available to the +/// Creates a [Sprite] from the entity information available to the /// [LdtkEntity::bundle_entity] method. /// -/// Used for the `#[sprite_bundle]` attribute macro for `#[derive(LdtkEntity)]`. -/// See [LdtkEntity#sprite_bundle] for more info. -pub fn sprite_bundle_from_entity_info(tileset: Option<&Handle>) -> SpriteBundle { +/// Used for the `#[sprite]` attribute macro for `#[derive(LdtkEntity)]`. +/// See [LdtkEntity#sprite] for more info. +pub fn sprite_from_entity_info(tileset: Option<&Handle>) -> Sprite { let tileset = match tileset { Some(tileset) => tileset.clone(), None => { - warn!("EntityInstance needs a tileset to be bundled as a SpriteBundle"); - return SpriteBundle::default(); + warn!("EntityInstance needs a tileset to be inserted as a Sprite"); + return Sprite::default(); } }; - SpriteBundle { - texture: tileset, - ..Default::default() - } + Sprite::from_image(tileset) } #[cfg(test)]