From b59cec172d3ec0343b136f94b48b13abf3351337 Mon Sep 17 00:00:00 2001 From: 2ndbeam <2ndbeam@disroot.org> Date: Mon, 23 Mar 2026 14:06:36 +0300 Subject: [PATCH] feat: Barely working tilemap system - Added tilemap bundle - Added HALVED_METERS_PER_PIXEL constant --- assets/sprites/level/tilemap.png | Bin 0 -> 424 bytes src/layout/container.rs | 10 +++--- src/layout/door.rs | 6 ++-- src/layout/mod.rs | 1 + src/layout/systems.rs | 43 +++++++++++++++++++--- src/layout/tilemap.rs | 60 +++++++++++++++++++++++++++++++ src/lib.rs | 1 + src/player/mod.rs | 6 ++-- 8 files changed, 109 insertions(+), 18 deletions(-) create mode 100644 assets/sprites/level/tilemap.png create mode 100644 src/layout/tilemap.rs diff --git a/assets/sprites/level/tilemap.png b/assets/sprites/level/tilemap.png new file mode 100644 index 0000000000000000000000000000000000000000..0d2b8816f3e9eae35f3633d3031a737151044dbd GIT binary patch literal 424 zcmeAS@N?(olHy`uVBq!ia0vp^0zhoQ!VDx|6+TY^QVPi)LB0$ORcZ_j4J`}|zkosw zFBlj~4S*^V7#OT(FffQ0%-I!a1C)>m@Ck7R(ykgdX_kgc3MMUe?U7+YnORx?|NmEx zwr~T=F_r}R1v5B2yO9RsBze2Lu!|*jyasaEOFVsD*b8twVI=i$2C?t@a=vM}! zftUk`!64?PavqT3;OXKRB5^rcpoNJ|QB_q{AT6MYi7i=Uf#P9P5hjV41r3d?N{;TfUE!1^xp!_QY~?fC`m~yNwrEYN(E93 zMg~S^x&}tNhDITV23E#qR)z-J1_o9J2It$9c~Lav=BH$)RU&IJFtai>wlXz`XgK3A zB@?JY18ze}W^QV6Nn&mRRFAQ)k#UHDg%uDPnL+gAEn5~0)WhKE>gTe~DWM4f7^G~P literal 0 HcmV?d00001 diff --git a/src/layout/container.rs b/src/layout/container.rs index 2c0019e..91f72b4 100644 --- a/src/layout/container.rs +++ b/src/layout/container.rs @@ -2,13 +2,11 @@ use bevy::prelude::*; use bevy_rapier2d::prelude::*; use crate::{ - GameState, - PIXELS_PER_METER, - inventory::{ + GameState, HALVED_PIXELS_PER_METER, PIXELS_PER_METER, inventory::{ ActiveInventory, Inventory, item::Item, - }, + } }; use super::*; @@ -47,7 +45,7 @@ pub fn container_bundle( let image = asset_server.load(CRATE_CLOSED_ASSET); ( Container, - Transform::from_xyz(position.x, position.y - PIXELS_PER_METER * 0.5, 0.), + Transform::from_xyz(position.x, position.y - HALVED_PIXELS_PER_METER, 0.), Sprite::from_image(image), Inventory::new(inventory_size), Observer::new(on_container_interact), @@ -56,7 +54,7 @@ pub fn container_bundle( Spawn(( Collider::cuboid(PIXELS_PER_METER, PIXELS_PER_METER), Sensor, - Transform::from_xyz(0., PIXELS_PER_METER * 0.5, 0.), + Transform::from_xyz(0., HALVED_PIXELS_PER_METER, 0.), )), )), ) diff --git a/src/layout/door.rs b/src/layout/door.rs index ddd849f..426a1ed 100644 --- a/src/layout/door.rs +++ b/src/layout/door.rs @@ -1,7 +1,7 @@ use bevy::prelude::*; use bevy_rapier2d::prelude::*; -use crate::PIXELS_PER_METER; +use crate::{PIXELS_PER_METER, HALVED_PIXELS_PER_METER}; use super::*; @@ -43,7 +43,7 @@ fn on_door_interact( for child in children { if let Ok((mut sprite, mut transform)) = sprite_query.get_mut(*child) { let (image, translation) = if was_opened { (DOOR_CLOSED_ASSET, 0.) } - else { (DOOR_OPENED_ASSET, door.0 as f32 * PIXELS_PER_METER * 0.5) }; + else { (DOOR_OPENED_ASSET, door.0 as f32 * HALVED_PIXELS_PER_METER) }; sprite.image = asset_server.load(image); transform.translation.x = translation; break; @@ -72,7 +72,7 @@ pub fn door_bundle(asset_server: &Res, position: Vec2, facing_left: Observer::new(on_door_interact), children![ ( - Collider::cuboid(PIXELS_PER_METER * 0.5, PIXELS_PER_METER), + Collider::cuboid(HALVED_PIXELS_PER_METER, PIXELS_PER_METER), Sensor, Transform::from_xyz(0., 0., 0.), ), diff --git a/src/layout/mod.rs b/src/layout/mod.rs index 6a55002..3f5a457 100644 --- a/src/layout/mod.rs +++ b/src/layout/mod.rs @@ -3,6 +3,7 @@ use bevy::prelude::*; pub mod container; pub mod door; pub mod systems; +pub mod tilemap; #[derive(Component, Debug, PartialEq, Eq, Default, Clone, Copy, Reflect)] #[reflect(Component, Debug, PartialEq, Default, Clone)] diff --git a/src/layout/systems.rs b/src/layout/systems.rs index 5d42f10..a5968e4 100644 --- a/src/layout/systems.rs +++ b/src/layout/systems.rs @@ -5,8 +5,7 @@ use bevy::{ use bevy_rapier2d::prelude::*; use crate::{ - inventory::item::Item, - player::Player, + HALVED_PIXELS_PER_METER, PIXELS_PER_METER, inventory::item::Item, player::Player }; use super::*; @@ -73,8 +72,42 @@ pub fn setup_world( Item::new_positioned(uvec2(2, 3), uvec2(6, 2)), Item::new_positioned(uvec2(4, 4), uvec2(0, 4)), ]; - commands.spawn(door::door_bundle(&asset_server, vec2(16., 0.), true)); - commands.spawn(door::door_bundle(&asset_server, vec2(48., 0.), false)); - commands.spawn(door::door_bundle(&asset_server, vec2(80., 0.), false)).insert(Locked); + + // floor + let mut tiles = (0..16).map(|x| { + (0, uvec2(x, 1)) + }).collect::>(); + + // ceiling + tiles.extend((0..16).map(|x| { + (0, uvec2(x, 5)) + })); + + // walls + tiles.extend([ + (0, 4), (0, 3), (0, 2), + (15, 4), (15, 3), (15, 2), + ].iter().map(|(x, y)| { + (1, uvec2(*x, *y)) + })); + + // wall connectors + tiles.extend([ + (13, 4), (11, 4), (9, 4), + ].iter().map(|(x, y)| { + (2, uvec2(*x, *y)) + })); + + let colliders: Vec<(Collider, Vec2)> = vec![ + (Collider::cuboid(HALVED_PIXELS_PER_METER, PIXELS_PER_METER * 1.5), + vec2(HALVED_PIXELS_PER_METER, HALVED_PIXELS_PER_METER)), + (Collider::cuboid(HALVED_PIXELS_PER_METER, PIXELS_PER_METER * 1.5), + vec2(PIXELS_PER_METER * 15.5, HALVED_PIXELS_PER_METER)), + ]; + + commands.spawn(door::door_bundle(&asset_server, vec2(PIXELS_PER_METER * 1.5, 0.), true)); + commands.spawn(door::door_bundle(&asset_server, vec2(PIXELS_PER_METER * 3.5, 0.), false)); + commands.spawn(door::door_bundle(&asset_server, vec2(PIXELS_PER_METER * 5.5, 0.), false)).insert(Locked); commands.spawn(container::container_bundle(&asset_server, vec2(-32., 0.), uvec2(8, 8), items)); + commands.spawn(tilemap::tilemap_bundle(&asset_server, uvec2(16, 6), tiles, colliders)); } diff --git a/src/layout/tilemap.rs b/src/layout/tilemap.rs new file mode 100644 index 0000000..b80cde3 --- /dev/null +++ b/src/layout/tilemap.rs @@ -0,0 +1,60 @@ +use bevy::{ + image::{ + ImageArrayLayout, + ImageLoaderSettings, + }, + prelude::*, + sprite_render::{ + TileData, + TilemapChunk, + TilemapChunkTileData, + }, +}; +use bevy_rapier2d::prelude::*; + +use crate::{HALVED_PIXELS_PER_METER, PIXELS_PER_METER}; + +const TILEMAP_PATH: &'static str = "sprites/level/tilemap.png"; +const TILE_DISPLAY_SIZE: UVec2 = UVec2::splat(PIXELS_PER_METER as u32); + +#[derive(Component, Debug, PartialEq, Eq, Default, Clone, Copy, Reflect)] +#[reflect(Component, Debug, PartialEq, Default, Clone)] +pub struct Tilemap; + +pub fn tilemap_bundle( + asset_server: &Res, + size: UVec2, + tiles: Vec<(u16, UVec2)>, + colliders: Vec<(Collider, Vec2)>, +) -> impl Bundle { + let tile_data: Vec> = (0..size.element_product()).map(|xy| { + if let Some((id, _)) = tiles.iter().find(|(_, pos)| pos.x == xy % size.x && pos.y == xy / size.x) { + Some(TileData::from_tileset_index(*id)) + } else { None } + }).collect(); + ( + Tilemap, + TilemapChunk { + chunk_size: size, + tile_display_size: TILE_DISPLAY_SIZE, + tileset: asset_server.load_with_settings( + TILEMAP_PATH, + |settings: &mut ImageLoaderSettings| { + settings.array_layout = Some(ImageArrayLayout::RowCount { rows: 3 }) + }, + ), + ..default() + }, + TilemapChunkTileData(tile_data), + Children::spawn(SpawnIter(colliders.into_iter() + .map(move |(collider, pos)| {( + collider.clone(), + Transform::from_xyz( + pos.x - HALVED_PIXELS_PER_METER * size.x as f32, + pos.y, + 0. + ), + )}) + )), + ) +} diff --git a/src/lib.rs b/src/lib.rs index 9382ba8..505da91 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -16,6 +16,7 @@ mod tests; pub mod ui; pub const PIXELS_PER_METER: f32 = 16.0; +pub const HALVED_PIXELS_PER_METER: f32 = PIXELS_PER_METER * 0.5; pub struct ExpeditionPlugin; diff --git a/src/player/mod.rs b/src/player/mod.rs index 841d711..9a262ed 100644 --- a/src/player/mod.rs +++ b/src/player/mod.rs @@ -2,9 +2,7 @@ use bevy::prelude::*; use bevy_rapier2d::prelude::*; use crate::{ - input::InputAction as Action, - PIXELS_PER_METER, - inventory::Inventory, + HALVED_PIXELS_PER_METER, PIXELS_PER_METER, input::InputAction as Action, inventory::Inventory }; pub mod systems; @@ -33,7 +31,7 @@ pub fn player_bundle(asset_server: &Res) -> impl Bundle { RigidBody::KinematicPositionBased, KinematicCharacterController::default(), ActiveCollisionTypes::default() | ActiveCollisionTypes::KINEMATIC_STATIC, - Collider::cuboid(PIXELS_PER_METER * 0.5, PIXELS_PER_METER), + Collider::cuboid(HALVED_PIXELS_PER_METER, PIXELS_PER_METER), ActiveEvents::COLLISION_EVENTS, Sleeping::disabled(), children![