From 464d8dc8bee32e09acbe36e2b87c5dc4b11563cd Mon Sep 17 00:00:00 2001 From: crumblingstatue Date: Sat, 15 Apr 2023 22:47:53 +0200 Subject: [PATCH] Very basic inventory --- res/graphics/items/woodpick.png | Bin 0 -> 746 bytes res/graphics/ui/invframe.png | Bin 0 -> 1281 bytes src/app.rs | 54 +++++++++---- src/debug.rs | 9 ++- src/game.rs | 67 +++++++++++++--- src/inventory.rs | 130 ++++++++++++++++++++++++++++++++ src/main.rs | 1 + src/texture_atlas.rs | 7 +- src/tiles.rs | 1 - tiles.dat | Bin 220 -> 220 bytes 10 files changed, 241 insertions(+), 28 deletions(-) create mode 100644 res/graphics/items/woodpick.png create mode 100644 res/graphics/ui/invframe.png create mode 100644 src/inventory.rs diff --git a/res/graphics/items/woodpick.png b/res/graphics/items/woodpick.png new file mode 100644 index 0000000000000000000000000000000000000000..1cc34da9265e6c18de3dbcb90111b250eec74e1b GIT binary patch literal 746 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANNfEt$^F0iMpz3I#>^X_+~x z3=A3*YbV-z9Cna78h^PA3g+~(>mTl_pvbd%tve0RTXjG}e&M(}vwy0?8^)+Q5 zJlKD9Rde^|b$siZ6n-#1di7|@3nkTm`kGrhK0eqX|NforyL*gIt52C2Phc>)Yh<)? z$&AzMyZ)}{P-sbP5u7|Ta{lBcCN{^f+t$?V?f$IuzPP?machFn0d*nuh`Sp)%sbM} z)>=KUeZ--CTI-|b#}-F%mAWUp9(|I2KIt&i`5uXzXKV^vB6PlPxO8|;PR5bTM*>4H zYsR10xu)peqcx$@Yl{8<9ZGPFk9=lz)^N#&4pk3?i0WLPlEkdd1Kk-ZTtIkch@rgnBS$dl7FWkPpKi%r@UxwCCMeEjXtMg=FU|>t~c6VX;4}uH! zE}zW6z`$AH5n0T@z%2~Ij105pNH8!ku$OrHy0SlK;TM+I7n&>ih=GCOxu=U`NW|f{ z(+v5V4R~B-xjQ?1=L&8t;#zlrv$}PjQudXJd!v{6y%f>(Zhm`XZOB8xCwtbvm)B+p z*Sxx~*Yi^QezAu-4BLNSUTGcBJl%nB&YJ`37UF6`0f*#|b2BhJTN&QCnI)xSUFECL z7ze&P?JsIN{60TZV9(oVAHa3~{}S#OR~n^k>Msifo^?1|wsxY)+9df!*`^X_+~x z3=A3*YbV-z9Cna78h^PA3g+~(>mTl_pvbd%tve0RTXjG}e&M(}vwy0?8^)+Q5 zJlKD9Rde^|b$siZ6n-#1di7|@3nkTm`kGrhK0eqX|NforyL*gIt52C2Phc>)Yh<)? z$&AzMyZ)}{P-sbP5u7|Ta{lBcCN{^f+t$?V?f$IuzPP?machFn0d*nuh`Sp)%sbM} z)>=KUeZ--CTI-|b#}-F%mAWUp9(|I2KIt&i`5uXzXKV^vB6PlPxO8|;PR5bTM*>4H zYsR10xu)peqcx$@Yl{8<9ZGPFk9=lz)^N#&4pk3?i0WLPlEkdd1Kk-ZTtIkch@rgnBS$dl7FWkPpKi%r@UxwCCMeEjXtMg=FU|>t~c6VX;4}uH! zE}zW6z`$AH5n0T@z%2~Ij105pNH8!ku$OrHy0SlK;TJX%mc3!$#lXPy&(p;*B;xSV zX}%rOsS?NQKc}hPKbi7r>s{Y#%Wf{sd3i97b-hxSZ=|E(mTes!?O_4@a%+YtE?{-#qiI_*0c|RTjU|=ly#>*!`)uv3dXb-&F7E z^Cs`i;afao;Z^AkC4MJfOQteGsxDJ%Zpd~oOIWt$DREp)|W{e{I8KP^AB;_7m(Ba@rX z+x?Gv$QiQxN7I^V+$OVSpKWthj7@p|J6Vcbxuf=GX08 z{K5W3_w4Oc%Gd2vJbEu~a)64Tz^e$^km@HB-fUxL+)OD<-LG&w6L= zu=&5h+W9Thv(I}mU3$8G+tM3W<#rnNGTA-9zQ6y@Y`FevmXU0zrZO_UG0OSGV7Yv2C5vzuW!3$Ri}F>Zdq~s_w_jbC+;yPELRB{T`2uu z{P5}YxGBa*o$uP-T5hmeF8af>?At|ed?$D;n#j^T?d06}`s$Rjb^FU*<+j}p=~^wZ z)1>z>+sqQq%Vs-ktDo=Ry*|%gKlrH3-f7LBPJMHo*>l|ENU{i*>%Sf4{T*UzOI-{6 zj@?-2Y&rk9w|=Ldsfnc1dH0pqb?4o)IDPkStju}W^J$$zj-7fZp7F@NEA>b%*%dqa vX2qdr#?f1(bgyZr&S7rnEDkyUIR3Vt))raz-y0bi7#KWV{an^LB{Ts5csyc} literal 0 HcmV?d00001 diff --git a/src/app.rs b/src/app.rs index 31e7b91..7b2a3dc 100644 --- a/src/app.rs +++ b/src/app.rs @@ -5,10 +5,10 @@ use gamedebug_core::{imm, imm_dbg}; use sfml::{ audio::SoundSource, graphics::{ - BlendMode, Color, Rect, RenderStates, RenderTarget, RenderTexture, RenderWindow, Sprite, - Transformable, View, + BlendMode, Color, Rect, RectangleShape, RenderStates, RenderTarget, RenderTexture, + RenderWindow, Shape, Sprite, Transformable, View, }, - system::Vector2u, + system::{Vector2, Vector2u}, window::{Event, Key}, }; @@ -17,6 +17,7 @@ use crate::{ game::{for_each_tile_on_screen, Biome, GameState}, graphics::{self, ScreenSc, ScreenVec}, input::Input, + inventory::TileLayer, math::{center_offset, TILE_SIZE}, res::Res, CliArgs, @@ -231,15 +232,22 @@ impl App { self.game.world.player.col_en.en.pos.y = wpos.y as i32; } if self.input.lmb_down { - let t = self.game.world.tile_at_mut(mouse_tpos, &self.game.worldgen); - t.mid = 0; - t.fg = 0; - } else if self.input.rmb_down { - let t = self.game.world.tile_at_mut(mouse_tpos, &self.game.worldgen); - if self.game.tile_to_place != 7 { - t.mid = self.game.tile_to_place; - } else { - t.bg = self.game.tile_to_place; + let active_slot = &self.game.inventory.slots[self.game.selected_inv_slot]; + if active_slot.qty != 0 { + let def = &self.game.itemdb.db[active_slot.id as usize]; + let t = self.game.world.tile_at_mut(mouse_tpos, &self.game.worldgen); + match &def.use_action { + crate::inventory::UseAction::PlaceTile { layer, id } => match layer { + TileLayer::Bg => t.bg = *id, + TileLayer::Mid => t.mid = *id, + TileLayer::Fg => t.fg = *id, + }, + crate::inventory::UseAction::RemoveTile { layer } => match layer { + TileLayer::Bg => t.bg = 0, + TileLayer::Mid => t.mid = 0, + TileLayer::Fg => t.fg = 0, + }, + } } } if self.game.camera_offset.y > 643_000 { @@ -262,7 +270,7 @@ impl App { } } } - self.game.update(); + self.game.update(&self.input); } fn do_freecam(&mut self) { @@ -305,6 +313,18 @@ impl App { self.light_map.display(); spr.set_texture(self.light_map.texture(), false); self.rw.draw_with_renderstates(&spr, &rst); + drop(spr); + // Draw ui on top of in-game scene + self.rt.clear(Color::TRANSPARENT); + let ui_dims = Vector2 { + x: (self.rw.size().x / self.scale as u32) as f32, + y: (self.rw.size().y / self.scale as u32) as f32, + }; + self.game.draw_ui(&mut self.rt, &self.res, ui_dims); + self.rt.display(); + let mut spr = Sprite::with_texture(self.rt.texture()); + spr.set_scale((self.scale as f32, self.scale as f32)); + self.rw.draw(&spr); self.sf_egui .do_frame(|ctx| { debug::do_debug_ui( @@ -317,6 +337,14 @@ impl App { }) .unwrap(); self.sf_egui.draw(&mut self.rw, None); + if self.debug.show_atlas { + let atlas = &self.res.atlas.tex; + let size = atlas.size(); + let mut rs = RectangleShape::from_rect(Rect::new(0., 0., size.x as f32, size.y as f32)); + rs.set_fill_color(Color::MAGENTA); + self.rw.draw(&rs); + self.rw.draw(&Sprite::with_texture(atlas)); + } self.rw.display(); } } diff --git a/src/debug.rs b/src/debug.rs index a6655f3..1ad62b1 100644 --- a/src/debug.rs +++ b/src/debug.rs @@ -1,4 +1,4 @@ -use egui_inspect::inspect; +use egui_inspect::{derive::Inspect, inspect}; use sfml::{audio::SoundSource, window::Key}; use crate::{ @@ -11,11 +11,12 @@ use crate::{ tiles::tiledb_edit_ui::tiledb_edit_ui, }; -#[derive(Default, Debug)] +#[derive(Default, Debug, Inspect)] pub struct DebugState { panel: bool, pub freecam: bool, tiledb_edit: bool, + pub show_atlas: bool, } impl DebugState { @@ -30,7 +31,7 @@ impl DebugState { } fn debug_panel_ui( - debug: &mut DebugState, + mut debug: &mut DebugState, mut game: &mut GameState, ctx: &egui::Context, res: &mut Res, @@ -85,7 +86,7 @@ fn debug_panel_ui( ui, scale, game, - debug.tiledb_edit + debug } }); if ui.button("Reload graphics").clicked() { diff --git a/src/game.rs b/src/game.rs index ab2c282..81789e0 100644 --- a/src/game.rs +++ b/src/game.rs @@ -3,16 +3,21 @@ use std::path::PathBuf; use derivative::Derivative; use egui_inspect::derive::Inspect; use sfml::{ - graphics::{Color, RectangleShape, RenderTarget, RenderTexture, Shape, Sprite, Transformable}, - system::Vector2u, + graphics::{ + Color, Rect, RectangleShape, RenderTarget, RenderTexture, Shape, Sprite, Transformable, + }, + system::{Vector2f, Vector2u}, + window::Key, }; use crate::{ graphics::{ScreenSc, ScreenVec}, + input::Input, + inventory::{Inventory, ItemDb}, math::{smoothwave, wp_to_tp, WorldPos}, res::Res, tiles::TileDb, - world::{Tile, TileId, TilePos, World}, + world::{Tile, TilePos, World}, worldgen::Worldgen, }; @@ -22,7 +27,6 @@ pub struct GameState { pub camera_offset: WorldPos, pub world: World, pub gravity: f32, - pub tile_to_place: TileId, pub current_biome: Biome, pub prev_biome: Biome, #[derivative(Debug = "ignore")] @@ -31,6 +35,9 @@ pub struct GameState { pub ambient_light: u8, pub light_sources: Vec, pub tile_db: TileDb, + pub inventory: Inventory, + pub itemdb: ItemDb, + pub selected_inv_slot: usize, } #[derive(Debug, Inspect)] @@ -45,7 +52,22 @@ pub enum Biome { } impl GameState { - pub fn update(&mut self) { + pub fn update(&mut self, input: &Input) { + if input.pressed(Key::Num1) { + self.selected_inv_slot = 0; + } + if input.pressed(Key::Num2) { + self.selected_inv_slot = 1; + } + if input.pressed(Key::Num3) { + self.selected_inv_slot = 2; + } + if input.pressed(Key::Num4) { + self.selected_inv_slot = 3; + } + if input.pressed(Key::Num5) { + self.selected_inv_slot = 4; + } self.world.ticks += 1; } pub(crate) fn draw_world(&mut self, rt: &mut RenderTexture, res: &mut Res) { @@ -75,7 +97,7 @@ impl GameState { } }); } - pub fn draw_entities(&mut self, rw: &mut RenderTexture) { + pub fn draw_entities(&mut self, rt: &mut RenderTexture) { let (x, y, w, h) = self.world.player.col_en.en.xywh(); let mut rect_sh = RectangleShape::new(); rect_sh.set_position(( @@ -83,14 +105,39 @@ impl GameState { (y - self.camera_offset.y as i32) as f32, )); rect_sh.set_size((w as f32, h as f32)); - rw.draw(&rect_sh); + rt.draw(&rect_sh); rect_sh.set_size((2., 2.)); rect_sh.set_fill_color(Color::RED); rect_sh.set_position(( (self.world.player.col_en.en.pos.x - self.camera_offset.x as i32) as f32, (self.world.player.col_en.en.pos.y - self.camera_offset.y as i32) as f32, )); - rw.draw(&rect_sh); + rt.draw(&rect_sh); + } + + pub fn draw_ui(&mut self, rt: &mut RenderTexture, res: &Res, ui_dims: Vector2f) { + let mut s = Sprite::with_texture(&res.atlas.tex); + let mut rs = RectangleShape::from_rect(Rect::new(0., 0., 32., 32.)); + rs.set_outline_color(Color::YELLOW); + rs.set_outline_thickness(1.0); + rs.set_fill_color(Color::TRANSPARENT); + for (i, slot) in self.inventory.slots.iter().enumerate() { + s.set_texture_rect(res.atlas.rects["ui/invframe"].to_sf()); + let pos = ((i * 38) as f32 + 8.0, (ui_dims.y - 38.)); + s.set_position(pos); + rt.draw(&s); + let item_def = &self.itemdb.db[slot.id as usize]; + if let Some(rect) = res.atlas.rects.get(&item_def.graphic_name) { + s.set_texture_rect(rect.to_sf()); + rt.draw(&s); + } else { + log::error!("Missing rect for item {}", item_def.name); + } + if i == self.selected_inv_slot { + rs.set_position(pos); + rt.draw(&rs); + } + } } pub(crate) fn light_pass(&mut self, lightmap: &mut RenderTexture, res: &Res) { @@ -126,13 +173,15 @@ impl GameState { camera_offset: spawn_point, world: World::new(spawn_point, &world_name, path), gravity: 0.55, - tile_to_place: 1, current_biome: Biome::Surface, prev_biome: Biome::Surface, worldgen: Worldgen::from_seed(0), ambient_light: 0, light_sources: Vec::new(), tile_db, + inventory: Inventory::new_debug(), + itemdb: ItemDb::default(), + selected_inv_slot: 0, } } } diff --git a/src/inventory.rs b/src/inventory.rs new file mode 100644 index 0000000..7922a1d --- /dev/null +++ b/src/inventory.rs @@ -0,0 +1,130 @@ +use egui_inspect::derive::Inspect; + +use crate::{math::IntRect, world::TileId}; + +/// We won't have more than 65535 different items +pub type ItemId = u16; +/// We won't have more than 65535 item quantity in a single slot +pub type ItemQty = u16; + +/// Inventory slot +#[derive(Debug, Inspect)] +pub struct Slot { + pub id: ItemId, + pub qty: ItemQty, +} + +#[derive(Debug, Inspect)] +pub struct Inventory { + pub slots: Vec, +} +impl Inventory { + /// A new inventory filled with some debug items + pub(crate) fn new_debug() -> Inventory { + Self { + slots: vec![ + Slot { + id: items::WOOD_PICK, + qty: 1, + }, + Slot { + id: items::DIRT_BLOCK, + qty: 100, + }, + Slot { + id: items::TORCH, + qty: 100, + }, + Slot { + id: items::PLATFORM, + qty: 100, + }, + ], + } + } +} + +#[derive(Debug, Inspect)] +pub struct ItemDef { + pub name: String, + pub graphic_name: String, + pub tex_rect: IntRect, + #[opaque] + pub use_action: UseAction, + pub consumable: bool, +} + +#[derive(Debug, Inspect, PartialEq)] +pub enum TileLayer { + Bg, + Mid, + Fg, +} + +#[derive(Debug)] +pub enum UseAction { + PlaceTile { layer: TileLayer, id: TileId }, + RemoveTile { layer: TileLayer }, +} + +#[derive(Debug, Inspect)] +pub struct ItemDb { + pub db: Vec, +} + +impl Default for ItemDb { + fn default() -> Self { + Self { + db: vec![ + ItemDef { + name: String::from("Dirt Block"), + graphic_name: String::from("tiles/dirt"), + tex_rect: IntRect::default(), + use_action: UseAction::PlaceTile { + layer: TileLayer::Mid, + id: 3, + }, + consumable: true, + }, + ItemDef { + name: String::from("Torch"), + graphic_name: String::from("tiles/torch"), + tex_rect: IntRect::default(), + use_action: UseAction::PlaceTile { + layer: TileLayer::Mid, + id: 4, + }, + consumable: true, + }, + ItemDef { + name: String::from("Platform"), + graphic_name: String::from("tiles/platform"), + tex_rect: IntRect::default(), + use_action: UseAction::PlaceTile { + layer: TileLayer::Mid, + id: 5, + }, + consumable: true, + }, + ItemDef { + name: String::from("Wood Pick"), + graphic_name: String::from("items/woodpick"), + tex_rect: IntRect::default(), + use_action: UseAction::RemoveTile { + layer: TileLayer::Mid, + }, + consumable: true, + }, + ], + } + } +} + +pub mod items { + use super::ItemId; + + pub const DIRT_BLOCK: ItemId = 0; + pub const TORCH: ItemId = 1; + pub const PLATFORM: ItemId = 2; + pub const WOOD_PICK: ItemId = 3; +} diff --git a/src/main.rs b/src/main.rs index c417982..b6fa0d1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,6 +4,7 @@ mod debug; mod game; mod graphics; mod input; +mod inventory; mod math; mod player; mod res; diff --git a/src/texture_atlas.rs b/src/texture_atlas.rs index a4535c6..0c2551e 100644 --- a/src/texture_atlas.rs +++ b/src/texture_atlas.rs @@ -20,7 +20,7 @@ impl AtlasBundle { max_height: 4096, allow_rotation: false, border_padding: 0, - texture_padding: 1, + texture_padding: 0, texture_extrusion: 0, trim: true, texture_outlines: false, @@ -34,6 +34,11 @@ impl AtlasBundle { }); let mut rects = HashMap::new(); let mut tex = Texture::new().unwrap(); + log::info!( + "Texture atlas size is: {}x{}", + packer.width(), + packer.height() + ); if !tex.create(packer.width(), packer.height()) { panic!("Failed to create texture"); } diff --git a/src/tiles.rs b/src/tiles.rs index 53ca4b9..fbdbd26 100644 --- a/src/tiles.rs +++ b/src/tiles.rs @@ -19,7 +19,6 @@ pub struct TileDef { pub light: Option, /// Platform behavior: Horizontally passable, vertically passable upwards pub platform: bool, - #[serde(default)] pub graphic_name: String, pub tex_rect: IntRect, } diff --git a/tiles.dat b/tiles.dat index 9e30cc01d1e5860e3a72637b345f80cbee2eab43..f42778ff49e3f641140df6b6a0b6ccee8ece22c6 100644 GIT binary patch delta 108 zcmcb^c!zO