From 2f727e403d92e81dfc143fd53505304732442473 Mon Sep 17 00:00:00 2001 From: RobertoMaurizzi Date: Thu, 17 Jul 2025 17:00:51 +0800 Subject: [PATCH] =?UTF-8?q?finally=20understand=20how=20to=20remap=20coord?= =?UTF-8?q?inates=20between=20LDtk=20and=20Bevy=20=F0=9F=98=B5=E2=80=8D?= =?UTF-8?q?=F0=9F=92=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/demo/level.rs | 168 +++++++++++++++++++++++++--------------------- 1 file changed, 92 insertions(+), 76 deletions(-) diff --git a/src/demo/level.rs b/src/demo/level.rs index 0a37418..618c650 100644 --- a/src/demo/level.rs +++ b/src/demo/level.rs @@ -6,7 +6,11 @@ use bevy::{ prelude::*, window::PrimaryWindow, }; -use bevy_ecs_ldtk::{ldtk::NeighbourLevel, prelude::*}; +use bevy_ecs_ldtk::{ + ldtk::{NeighbourLevel, TileInstance}, + prelude::*, + utils::int_grid_index_to_grid_coords, +}; use crate::{ asset_tracking::LoadResource, audio::music, demo::player::PlayerAssets, screens::Screen, @@ -17,6 +21,7 @@ use super::player::Player; pub(super) fn plugin(app: &mut App) { app.add_plugins(LdtkPlugin) .insert_resource(LevelSelection::iid("d53f9950-c640-11ed-8430-4942c04951ff")) + // .insert_resource(LevelSelection::iid("34f51d20-8990-11ee-b0d1-cfeb0e9e30f6")) .insert_resource(LdtkSettings { level_spawn_behavior: LevelSpawnBehavior::UseWorldTranslation { load_level_neighbors: true, @@ -40,7 +45,8 @@ pub(super) fn plugin(app: &mut App) { level_selection_follow_player, cache_wall_locations, pan_camera, - ), + ) + .chain(), ); } @@ -64,6 +70,7 @@ impl FromWorld for LevelAssets { Self { music: assets.load("audio/music/Fluffing A Duck.ogg"), world: assets.load("levels/world.ldtk").into(), + // world: assets.load("levels/tile-based-game.ldtk").into(), // world: assets.load("levels/collectathon.ldtk").into(), } } @@ -97,11 +104,13 @@ fn translate_grid_coords_entities( // TODO: what is this used for? Why it doesn't work for a moving Player? for (mut transform, grid_coords) in grid_coords_entities.iter_mut() { info!("Changed GridCoords: {grid_coords:?}"); + info!("Previous traslation: {:?}", transform.translation); transform.translation = (bevy_ecs_ldtk::utils::grid_coords_to_translation( *grid_coords, IVec2::splat(GRID_SIZE), )) .extend(transform.translation.z); + info!("Updated traslation: {:?}", transform.translation); } } @@ -155,6 +164,8 @@ pub fn convert_neighbors( #[reflect(Resource)] pub struct LevelWalls { wall_locations: HashSet, + level_tile_pos_x: i32, + level_tile_pos_y: i32, level_width: i32, level_height: i32, level_neighbours: HashMap, @@ -177,18 +188,36 @@ impl LevelWalls { "map for a level that is x: {} by y: {}", self.level_width, self.level_height ); - for y in (0..self.level_height) { + info!("player pos: {:?}", player_pos); + println!( + "level world coordinates: x: {} y: {}", + self.level_tile_pos_x, self.level_tile_pos_y + ); + // FIXME: kwwp aligned with MultiLevelWalls.in_wall.translated_coords + let player_translated_coords = GridCoords::new( + player_pos.x - self.level_tile_pos_x, + player_pos.y - (-self.level_tile_pos_y - self.level_height), + ); + println!("Player absolute coords: {:?}", *player_pos); + println!("Player relative coords: {player_translated_coords:?}"); + for y in (0..self.level_height).rev() { for x in 0..self.level_width { + // let coords = GridCoords::new(x + self.level_tile_pos_x, y + self.level_tile_pos_y); let coords = GridCoords::new(x, y); - if coords == *player_pos { + if coords.x == 0 { + print!("[X :{:03} Y: {:03}] ", coords.x, coords.y); + } + if coords == player_translated_coords { print!("@"); } else if self.in_wall(&coords) { print!("X"); } else { print!("_"); } + if coords.x == (self.level_width - 1) { + println!("[X :{:03} Y: {:03}] ", coords.x, coords.y); + } } - println!(" [y: {y:02}]"); } } } @@ -201,7 +230,23 @@ pub struct MultiLevelWalls { impl MultiLevelWalls { pub fn in_wall(&self, level: &LevelIid, grid_coords: &GridCoords) -> bool { - self.cache[level].in_wall(grid_coords) + let translated_coords = GridCoords::new( + // FIXME: x seems to work, y... not so much. + // Level UNDER the "zero level strip" by a level_height has: + // level world coordinates: x: -16 y: 0 + // Player absolute coords: GridCoords { x: -8, y: -1 } y should be 15 + // Player relative coords: GridCoords { x: 8, y: -1 } + // Level ABOVE the "zero level strip" by a level_height has: + // level world coordinates: x: 32 y: -32 + // Player absolute coords: GridCoords { x: 42, y: 17 } + // Player relative coords: GridCoords { x: 10, y: 17 } y should be 1 + // level world coordinates: x: 32 y: -16 + // Player absolute coords: GridCoords { x: 41, y: 16 } + // Player relative coords: GridCoords { x: 9, y: 16 } y should be 0 + grid_coords.x - self.cache[level].level_tile_pos_x, + grid_coords.y - (-self.cache[level].level_tile_pos_y - self.cache[level].level_height), + ); + self.cache[level].in_wall(&translated_coords) } pub fn debug_collisions(&self, level: &LevelIid, player_pos: &GridCoords) { if let Some(level) = self.cache.get(level) { @@ -218,68 +263,27 @@ pub fn spawn_level( window: Single<&Window, With>, level_assets: Res, ) { - let half_size = window.size() / 2.0; + // let half_size = window.size() / 2.0; commands.spawn(( Name::new("Ldtk level"), StateScoped(Screen::Gameplay), LdtkWorldBundle { ldtk_handle: level_assets.world.clone(), - transform: Transform::from_xyz(-half_size.x, half_size.y, 0.0), + // transform: Transform::from_xyz(-half_size.x, half_size.y, 0.0), ..Default::default() }, )); } -fn _old_cache_wall_locations( - level_selection: Res, - mut level_walls: ResMut, - mut level_events: EventReader, - walls: Query<&GridCoords, With>, - ldtk_project_entities: Query<&LdtkProjectHandle>, - ldtk_project_assets: Res>, -) -> Result { - for level_event in level_events.read() { - if let LevelEvent::Spawned(level_iid) = level_event { - let ldtk_project = ldtk_project_assets - .get(ldtk_project_entities.single()?) - .expect("LdtkProject should be loaded when level is spawned"); - let level = ldtk_project - .get_raw_level_by_iid(level_iid.get()) - .expect("spawned level should exist in project"); - - let wall_locations = walls.iter().copied().collect(); - - info!( - "loading level of dimension x: {} by y: {}", - level.px_wid, level.px_hei - ); - let new_level_walls = LevelWalls { - wall_locations, - level_width: level.px_wid / GRID_SIZE, - level_height: level.px_hei / GRID_SIZE, - ..Default::default() - }; - - *level_walls = new_level_walls; - info!( - "new level tile dimensions are x: {} y {}", - level_walls.level_width, level_walls.level_height - ); - level_walls.debug_collisions(&GridCoords::default()); - } - } - Ok(()) -} - fn cache_wall_locations( mut levels_wall_cache: ResMut, mut level_events: EventReader, - walls: Query<(&ChildOf, &GridCoords), With>, ldtk_project_entities: Query<&LdtkProjectHandle>, ldtk_project_assets: Res>, ) -> Result { let multi_level_walls = levels_wall_cache.into_inner(); + let pippo: TileInstance = TileInstance::default(); for level_event in level_events.read() { if let LevelEvent::Spawned(level_iid) = level_event { @@ -291,47 +295,60 @@ fn cache_wall_locations( .expect("spawned level should exist in project"); let mut wall_locations = HashSet::::default(); - info!("current level neighbours: {:?}", level.neighbours); + let mut last_coord: GridCoords = GridCoords::default(); + trace!("current level neighbours: {:?}", level.neighbours); + trace!( + "Level world coordinates: x [{}], y[{}]", + level.world_x, level.world_y + ); + + let level_tile_pos_x = level.world_x / GRID_SIZE; + let level_tile_pos_y = level.world_y / GRID_SIZE; + let level_tile_width = level.px_wid / GRID_SIZE; + trace!( + "Level tile coordinates: x [{}], y[{}]", + level_tile_pos_x, level_tile_pos_y + ); if let Some(layers) = level.layer_instances.clone() { // info!("layers: {:?}", layers); layers.iter().for_each(|field| { info!("Layer field: {:?}", field.identifier); if field.identifier == "Walls" { info!("Found walls layer: {:?}", field.int_grid_csv); - info!("Trying to format it"); - // FIXME: a .rev() here? It doesn't look necessary from what gets printed - // remember to fix the supposed "map dragging" too - for y in (0..(level.px_hei / GRID_SIZE)) { - for x in (0..(level.px_wid / GRID_SIZE)) { - let index = (y * level.px_wid / GRID_SIZE + x) as usize; - if let Some(value) = field.int_grid_csv.get(index) { - if *value == 1 { - print!("X"); - wall_locations.insert(GridCoords::new(x, y)); - } else { - print!("_"); - } - } + for (i, value) in field.int_grid_csv.iter().enumerate() { + let gc = int_grid_index_to_grid_coords( + i, + (level.px_wid / GRID_SIZE) as u32, + (level.px_hei / GRID_SIZE) as u32, + ); + let Some(gc) = gc else { + warn!("Invalid GridCoords for index {i}"); + continue; + }; + last_coord = GridCoords::new(gc.x, gc.y); + if last_coord.x == 0 { + print!("[X :{:03} Y: {:03}] ", last_coord.x, last_coord.y); + } + if *value == 1 { + print!("X"); + wall_locations.insert(last_coord); + } else { + print!("_"); + } + if last_coord.x == (level_tile_width - 1) { + println!(" [X :{:03} Y: {:03}]", last_coord.x, last_coord.y); } - println!(" [y: {y:02}]"); } } }); } - // level.iter_fields().for_each(|field| { - // info!("Field: {:?}", field); - // }); - // let wall_locations = walls.iter().map(|e| e.1).copied().collect(); - - info!( - "loading level of dimension x: {} by y: {}", - level.px_wid, level.px_hei - ); multi_level_walls.cache.insert( level_iid.clone(), // You'll need to clone the key since HashMap takes ownership LevelWalls { wall_locations, + level_tile_pos_x, + level_tile_pos_y, level_width: level.px_wid / GRID_SIZE, level_height: level.px_hei / GRID_SIZE, level_neighbours: convert_neighbors(&level.neighbours).unwrap_or_default(), // Convert neighbours to a HashMap @@ -344,7 +361,6 @@ fn cache_wall_locations( multi_level_walls.cache[level_iid].level_height, multi_level_walls.cache[level_iid].level_neighbours, ); - multi_level_walls.cache[level_iid].debug_collisions(&GridCoords::default()); } } Ok(())