Skip to content

Commit

Permalink
feat!: Implement proper item y-sorting
Browse files Browse the repository at this point in the history
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 Trouv/bevy_ecs_ldtk#276.
  • Loading branch information
PraxTube committed Dec 6, 2023
1 parent d658916 commit dcada77
Show file tree
Hide file tree
Showing 5 changed files with 154 additions and 35 deletions.
150 changes: 129 additions & 21 deletions assets/map/level.ldtk
Original file line number Diff line number Diff line change
Expand Up @@ -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": [] }]
}
]
},
Expand Down Expand Up @@ -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",
Expand Down
23 changes: 13 additions & 10 deletions src/item/mod.rs
Original file line number Diff line number Diff line change
@@ -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::<ItemBundle>("Item")
.add_systems(Update, (debug_items, add_item_ysort));
.add_systems(Update, add_item_ysort.run_if(in_state(GameState::Gaming)));
}
}

Expand Down Expand Up @@ -45,13 +52,9 @@ struct ItemBundle {

fn add_item_ysort(mut commands: Commands, q_items: Query<Entity, (With<Item>, Without<YSort>)>) {
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));
}
}
10 changes: 7 additions & 3 deletions src/world/camera.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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;
}
}

Expand Down
4 changes: 3 additions & 1 deletion src/world/map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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,
)
}

Expand Down
2 changes: 2 additions & 0 deletions src/world/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down

0 comments on commit dcada77

Please sign in to comment.