From 47035f1460ad9c603755145a5ee986cf60f22cd3 Mon Sep 17 00:00:00 2001 From: crumblingstatue Date: Sat, 8 Apr 2023 19:21:07 +0200 Subject: [PATCH] Implement platforms --- src/app.rs | 43 ++++++++++++++++++++++++++++++------ src/game/player.rs | 3 +++ src/tiles.rs | 25 ++++++++++++++++++--- src/tiles/tiledb_edit_ui.rs | 19 +++++++++++++++- tiles.dat | Bin 86 -> 109 bytes 5 files changed, 79 insertions(+), 11 deletions(-) diff --git a/src/app.rs b/src/app.rs index 4449e56..ffb8ff8 100644 --- a/src/app.rs +++ b/src/app.rs @@ -121,6 +121,7 @@ impl App { self.game.player.vspeed = -10.0; self.game.player.jumps_left = 0; } + self.game.player.down_intent = self.input.down(Key::S); let terminal_velocity = 60.0; self.game.player.vspeed = self .game @@ -130,14 +131,22 @@ impl App { let mut on_screen_tile_ents = Vec::new(); for_each_tile_on_screen(self.game.camera_offset, self.rt.size(), |tp, _sp| { let tid = self.game.world.tile_at_mut(tp, &self.game.worldgen).mid; - if !self.game.tile_db[tid].solid { + let tdef = &self.game.tile_db[tid]; + let Some(bb) = tdef.bb else { return; - } - let tsize = TILE_SIZE as i32; + }; let x = tp.x as i32 * TILE_SIZE as i32; let y = tp.y as i32 * TILE_SIZE as i32; - let en = s2dc::Entity::from_rect_corners(x, y, x + tsize, y + tsize); - on_screen_tile_ents.push(en); + let en = s2dc::Entity::from_rect_corners( + x + bb.x as i32, + y + bb.y as i32, + x + bb.w as i32, + y + bb.h as i32, + ); + on_screen_tile_ents.push(TileColEn { + col: en, + platform: tdef.platform, + }); }); imm_dbg!(on_screen_tile_ents.len()); self.game @@ -146,7 +155,18 @@ impl App { .move_y(self.game.player.vspeed, |player_en, off| { let mut col = false; for en in &on_screen_tile_ents { - if player_en.would_collide(en, off) { + if player_en.would_collide(&en.col, off) { + if en.platform { + if self.game.player.vspeed < 0. { + continue; + } + // If the player's feet are below the top of the platform, + // collision shouldn't happen + let player_feet = player_en.pos.y + player_en.bb.y; + if player_feet > en.col.pos.y || self.game.player.down_intent { + continue; + } + } col = true; if self.game.player.vspeed > 0. { self.game.player.jumps_left = 1; @@ -162,7 +182,10 @@ impl App { .move_x(self.game.player.hspeed, |player_en, off| { let mut col = false; for en in &on_screen_tile_ents { - if player_en.would_collide(en, off) { + if en.platform { + continue; + } + if player_en.would_collide(&en.col, off) { col = true; self.game.player.hspeed = 0.; } @@ -290,6 +313,12 @@ impl App { } } +/// Tile collision entity for doing physics +struct TileColEn { + col: s2dc::Entity, + platform: bool, +} + fn viewport_center_offset(rw_size: Vector2u, rt_size: Vector2u, scale: u8) -> ScreenVec { let rw_size = rw_size; let rt_size = rt_size * scale as u32; diff --git a/src/game/player.rs b/src/game/player.rs index c4ed36e..adbb5b0 100644 --- a/src/game/player.rs +++ b/src/game/player.rs @@ -13,6 +13,8 @@ pub struct Player { pub vspeed: f32, pub hspeed: f32, pub jumps_left: u8, + /// true if the player wants to jump down from a platform + pub down_intent: bool, } fn inspect_mobile_entity(en: &mut MobileEntity, ui: &mut egui::Ui, _id_src: u64) { @@ -32,6 +34,7 @@ impl Player { vspeed: 0.0, hspeed: 0.0, jumps_left: 0, + down_intent: false, } } #[allow(dead_code)] diff --git a/src/tiles.rs b/src/tiles.rs index e90a324..a2754d9 100644 --- a/src/tiles.rs +++ b/src/tiles.rs @@ -15,10 +15,27 @@ use crate::{ #[derive(Serialize, Deserialize, Default, Debug, Inspect)] pub struct TileDef { - pub solid: bool, + pub bb: Option, /// Whether the tile emits light, and the light source offset pub light: Option, pub atlas_offset: AtlasOffset, + /// Platform behavior: Horizontally passable, vertically passable upwards + pub platform: bool, +} + +const DEFAULT_TILE_BB: TileBb = TileBb { + x: 0, + y: 0, + w: TILE_SIZE, + h: TILE_SIZE, +}; + +#[derive(Serialize, Deserialize, Debug, Inspect, Clone, Copy)] +pub struct TileBb { + pub x: u8, + pub y: u8, + pub w: u8, + pub h: u8, } #[derive(Serialize, Deserialize, Debug, Inspect)] @@ -36,11 +53,12 @@ impl Default for TileDb { } const EMPTY: TileDef = TileDef { - solid: false, + bb: None, light: None, // Rendering empty tile is actually special cased, and no rendering is done. // But just in case, put the offset to UNKNOWN atlas_offset: UNKNOWN_ATLAS_OFF, + platform: false, }; impl Index for TileDb { @@ -76,12 +94,13 @@ impl Default for AtlasOffset { const UNKNOWN_ATLAS_OFF: AtlasOffset = AtlasOffset { x: 320, y: 0 }; static UNKNOWN_TILE: TileDef = TileDef { - solid: true, + bb: None, light: Some(ScreenVec { x: TILE_SIZE as ScreenSc / 2, y: TILE_SIZE as ScreenSc / 2, }), atlas_offset: UNKNOWN_ATLAS_OFF, + platform: false, }; const PATH: &str = "tiles.dat"; diff --git a/src/tiles/tiledb_edit_ui.rs b/src/tiles/tiledb_edit_ui.rs index 3ef3571..634eded 100644 --- a/src/tiles/tiledb_edit_ui.rs +++ b/src/tiles/tiledb_edit_ui.rs @@ -3,7 +3,7 @@ use crate::{ math::TILE_SIZE, }; -use super::TileDb; +use super::{TileDb, DEFAULT_TILE_BB}; pub fn tiledb_edit_ui(ctx: &egui::Context, tile_db: &mut TileDb) { egui::Window::new("Tiledb editor").show(ctx, |ui| { @@ -30,6 +30,23 @@ pub fn tiledb_edit_ui(ctx: &egui::Context, tile_db: &mut TileDb) { } } } + match &mut def.bb { + Some(bb) => { + ui.label("x"); + ui.add(egui::DragValue::new(&mut bb.x)); + ui.label("y"); + ui.add(egui::DragValue::new(&mut bb.y)); + ui.label("w"); + ui.add(egui::DragValue::new(&mut bb.w)); + ui.label("h"); + ui.add(egui::DragValue::new(&mut bb.h)); + } + None => { + if ui.button("Insert bb").clicked() { + def.bb = Some(DEFAULT_TILE_BB); + } + } + } } }); ui.separator(); diff --git a/tiles.dat b/tiles.dat index db95a3b85f357624251a4cc5caf67b443260f45c..075a56bbf817f57f1d7cf20a98a4bfa63127a6fb 100644 GIT binary patch literal 109 zcmbO@d&+?Wlg=_aFdUjPg@Hjq;lLyY1XF?G(3As{cv&Z%Wdt)}D&blV9GG-w0Z7q- WNoNi~Xoy*06)=++LHZIH4g&yGH89}- literal 86 zcmbO@d-9d=8nXBIGkG@UsBroei^ IvJ7xO0O_14S^xk5