From dcada7785cf130dc2a4a9cc277ce6eb670c005aa Mon Sep 17 00:00:00 2001 From: PraxTube Date: Wed, 6 Dec 2023 08:53:10 +0100 Subject: [PATCH] feat!: Implement proper item y-sorting This is achieved by using `YSort` and properly offsetting the value (taking into account the LDtk layer index and the parent z transform). Note that overlapping tiles in the same layer is not supported yet. The reason is simple: If you have a tile in layer A, which has an index of 3, then this tile will have a z value of 3 in bevy. However, if you have two tiles that are overlapping each other, one of them will have value 3 while the other will have value 4. That's why we are currently restricted to only non-overlapping tiles (which is totally fine for this project). More info at https://github.com/Trouv/bevy_ecs_ldtk/issues/276. --- assets/map/level.ldtk | 150 ++++++++++++++++++++++++++++++++++++------ src/item/mod.rs | 23 ++++--- src/world/camera.rs | 10 ++- src/world/map.rs | 4 +- src/world/mod.rs | 2 + 5 files changed, 154 insertions(+), 35 deletions(-) diff --git a/assets/map/level.ldtk b/assets/map/level.ldtk index 10edc09..5116544 100644 --- a/assets/map/level.ldtk +++ b/assets/map/level.ldtk @@ -315,6 +315,134 @@ "defUid": 42, "px": [864,96], "fieldInstances": [{ "__identifier": "item", "__type": "LocalEnum.Item", "__value": "Test", "__tile": null, "defUid": 44, "realEditorValues": [] }] + }, + { + "__identifier": "Item", + "__grid": [28,3], + "__pivot": [0,0], + "__tags": ["ItemSocket"], + "__tile": { "tilesetUid": 20, "x": 160, "y": 288, "w": 32, "h": 32 }, + "__smartColor": "#BE4A2F", + "__worldX": 896, + "__worldY": -928, + "iid": "16914950-8990-11ee-8902-353f5991adad", + "width": 32, + "height": 32, + "defUid": 42, + "px": [896,96], + "fieldInstances": [{ "__identifier": "item", "__type": "LocalEnum.Item", "__value": "Test", "__tile": null, "defUid": 44, "realEditorValues": [] }] + }, + { + "__identifier": "Item", + "__grid": [28,4], + "__pivot": [0,0], + "__tags": ["ItemSocket"], + "__tile": { "tilesetUid": 20, "x": 160, "y": 288, "w": 32, "h": 32 }, + "__smartColor": "#BE4A2F", + "__worldX": 896, + "__worldY": -896, + "iid": "18c392a0-8990-11ee-8902-71438e57a301", + "width": 32, + "height": 32, + "defUid": 42, + "px": [896,128], + "fieldInstances": [{ "__identifier": "item", "__type": "LocalEnum.Item", "__value": "Test", "__tile": null, "defUid": 44, "realEditorValues": [] }] + }, + { + "__identifier": "Item", + "__grid": [27,4], + "__pivot": [0,0], + "__tags": ["ItemSocket"], + "__tile": { "tilesetUid": 20, "x": 160, "y": 288, "w": 32, "h": 32 }, + "__smartColor": "#BE4A2F", + "__worldX": 864, + "__worldY": -896, + "iid": "19083cc0-8990-11ee-8902-e57fec953183", + "width": 32, + "height": 32, + "defUid": 42, + "px": [864,128], + "fieldInstances": [{ "__identifier": "item", "__type": "LocalEnum.Item", "__value": "Test", "__tile": null, "defUid": 44, "realEditorValues": [] }] + }, + { + "__identifier": "Item", + "__grid": [29,3], + "__pivot": [0,0], + "__tags": ["ItemSocket"], + "__tile": { "tilesetUid": 20, "x": 160, "y": 288, "w": 32, "h": 32 }, + "__smartColor": "#BE4A2F", + "__worldX": 928, + "__worldY": -928, + "iid": "197fddc0-8990-11ee-8902-0967e94124f0", + "width": 32, + "height": 32, + "defUid": 42, + "px": [928,96], + "fieldInstances": [{ "__identifier": "item", "__type": "LocalEnum.Item", "__value": "Test", "__tile": null, "defUid": 44, "realEditorValues": [] }] + }, + { + "__identifier": "Item", + "__grid": [29,4], + "__pivot": [0,0], + "__tags": ["ItemSocket"], + "__tile": { "tilesetUid": 20, "x": 160, "y": 288, "w": 32, "h": 32 }, + "__smartColor": "#BE4A2F", + "__worldX": 928, + "__worldY": -896, + "iid": "19a36b50-8990-11ee-8902-e177a33cadd2", + "width": 32, + "height": 32, + "defUid": 42, + "px": [928,128], + "fieldInstances": [{ "__identifier": "item", "__type": "LocalEnum.Item", "__value": "Test", "__tile": null, "defUid": 44, "realEditorValues": [] }] + }, + { + "__identifier": "Item", + "__grid": [27,2], + "__pivot": [0,0], + "__tags": ["ItemSocket"], + "__tile": { "tilesetUid": 20, "x": 160, "y": 288, "w": 32, "h": 32 }, + "__smartColor": "#BE4A2F", + "__worldX": 864, + "__worldY": -960, + "iid": "19ead490-8990-11ee-8902-ab9f9e96f7f2", + "width": 32, + "height": 32, + "defUid": 42, + "px": [864,64], + "fieldInstances": [{ "__identifier": "item", "__type": "LocalEnum.Item", "__value": "Test", "__tile": null, "defUid": 44, "realEditorValues": [] }] + }, + { + "__identifier": "Item", + "__grid": [29,2], + "__pivot": [0,0], + "__tags": ["ItemSocket"], + "__tile": { "tilesetUid": 20, "x": 160, "y": 288, "w": 32, "h": 32 }, + "__smartColor": "#BE4A2F", + "__worldX": 928, + "__worldY": -960, + "iid": "1ac30c20-8990-11ee-8902-9bb8a131be2e", + "width": 32, + "height": 32, + "defUid": 42, + "px": [928,64], + "fieldInstances": [{ "__identifier": "item", "__type": "LocalEnum.Item", "__value": "Test", "__tile": null, "defUid": 44, "realEditorValues": [] }] + }, + { + "__identifier": "Item", + "__grid": [28,2], + "__pivot": [0,0], + "__tags": ["ItemSocket"], + "__tile": { "tilesetUid": 20, "x": 160, "y": 288, "w": 32, "h": 32 }, + "__smartColor": "#BE4A2F", + "__worldX": 896, + "__worldY": -960, + "iid": "1af60300-8990-11ee-8902-cf0e82208d56", + "width": 32, + "height": 32, + "defUid": 42, + "px": [896,64], + "fieldInstances": [{ "__identifier": "item", "__type": "LocalEnum.Item", "__value": "Test", "__tile": null, "defUid": 44, "realEditorValues": [] }] } ] }, @@ -3836,27 +3964,7 @@ "seed": 4912828, "overrideTilesetUid": null, "gridTiles": [], - "entityInstances": [ - { - "__identifier": "Item", - "__grid": [8,23], - "__pivot": [0,0], - "__tags": ["ItemSocket"], - "__tile": { "tilesetUid": 20, "x": 160, "y": 288, "w": 32, "h": 32 }, - "__smartColor": "#BE4A2F", - "__worldX": 1280, - "__worldY": -1312, - "iid": "aa44fce0-8990-11ee-bcec-d7294c8c227a", - "width": 32, - "height": 32, - "defUid": 42, - "px": [256,736], - "fieldInstances": [{ "__identifier": "item", "__type": "LocalEnum.Item", "__value": "Fulgur", "__tile": null, "defUid": 44, "realEditorValues": [{ - "id": "V_String", - "params": ["Fulgur"] - }] }] - } - ] + "entityInstances": [] }, { "__identifier": "Props_tileset", diff --git a/src/item/mod.rs b/src/item/mod.rs index 979b5bb..f2e4f72 100644 --- a/src/item/mod.rs +++ b/src/item/mod.rs @@ -1,14 +1,21 @@ use bevy::prelude::*; use bevy_ecs_ldtk::prelude::*; -use crate::world::camera::YSort; +use crate::world::camera::{YSort, TRANSLATION_TO_PIXEL}; +use crate::world::BACKGROUND_ZINDEX_ABS; +use crate::GameState; + +// The index of the layer the items reside in. +// If the LDtk layers are changed (rearanged or added/removed), +// then this will need to be changed accordingly. +const ITEM_LAYER_ZINDEX_ABS: f32 = 3.0; pub struct ItemPlugin; impl Plugin for ItemPlugin { fn build(&self, app: &mut App) { app.register_ldtk_entity::("Item") - .add_systems(Update, (debug_items, add_item_ysort)); + .add_systems(Update, add_item_ysort.run_if(in_state(GameState::Gaming))); } } @@ -45,13 +52,9 @@ struct ItemBundle { fn add_item_ysort(mut commands: Commands, q_items: Query, Without)>) { for entity in &q_items { - commands.entity(entity).insert(YSort(0.0)); - } -} - -fn debug_items(mut q_items: Query<(&Item, &mut Transform)>) { - for (item, mut transform) in &mut q_items { - transform.translation += Vec3::new(0.1, 0.0, 0.0); - info!("{:?}, {:?}", transform, item); + let offset = -ITEM_LAYER_ZINDEX_ABS + BACKGROUND_ZINDEX_ABS; + commands + .entity(entity) + .insert(YSort(-10.0 * TRANSLATION_TO_PIXEL + offset)); } } diff --git a/src/world/camera.rs b/src/world/camera.rs index 956b67b..3c24c2b 100644 --- a/src/world/camera.rs +++ b/src/world/camera.rs @@ -6,6 +6,10 @@ use crate::player::input::PlayerInput; use crate::player::{Player, PlayerState}; use crate::GameState; +// How much `1.0` in bevy coordinates translates to the pixels of a sprite. +// Only relevant for the ysorting. +pub const TRANSLATION_TO_PIXEL: f32 = 0.0001; + pub struct CameraPlugin; impl Plugin for CameraPlugin { @@ -25,9 +29,9 @@ pub struct MainCamera; #[derive(Component)] pub struct YSort(pub f32); -pub fn apply_y_sort(mut q_transforms: Query<(&mut Transform, &YSort)>) { - for (mut transform, ysort) in &mut q_transforms { - transform.translation.z = ysort.0 - transform.translation.y * 0.0001; +pub fn apply_y_sort(mut q_transforms: Query<(&mut Transform, &GlobalTransform, &YSort)>) { + for (mut transform, global_transform, ysort) in &mut q_transforms { + transform.translation.z = ysort.0 - global_transform.translation().y * TRANSLATION_TO_PIXEL; } } diff --git a/src/world/map.rs b/src/world/map.rs index d1e92c2..e39a7cb 100644 --- a/src/world/map.rs +++ b/src/world/map.rs @@ -6,6 +6,8 @@ use bevy_ecs_ldtk::prelude::*; use crate::player::Player; use crate::{GameAssets, GameState}; +use super::BACKGROUND_ZINDEX_ABS; + const CHUNK_SIZE: f32 = 32.0 * 32.0; const CAMERA_SIZE_X: f32 = 400.0; const CAMERA_SIZE_Y: f32 = 300.0; @@ -29,7 +31,7 @@ fn map_indices_to_world_coords(x_index: i32, y_index: i32) -> Vec3 { Vec3::new( x_index as f32 * CHUNK_SIZE, y_index as f32 * CHUNK_SIZE, - -1_000.0, + -BACKGROUND_ZINDEX_ABS, ) } diff --git a/src/world/mod.rs b/src/world/mod.rs index 88d0786..02a7543 100644 --- a/src/world/mod.rs +++ b/src/world/mod.rs @@ -8,6 +8,8 @@ pub use camera::MainCamera; use bevy::prelude::*; use bevy_rapier2d::prelude::*; +pub const BACKGROUND_ZINDEX_ABS: f32 = 1_000.0; + pub struct WorldPlugin; impl Plugin for WorldPlugin {