From 8b872c4318c812d593daf31b70126455d890ba8f Mon Sep 17 00:00:00 2001 From: Jakob Meier Date: Fri, 24 Feb 2023 21:18:49 +0100 Subject: [PATCH] Started working on inventory --- src/blocks.rs | 1 + src/main.rs | 23 +--- src/screens/# | 238 --------------------------------------- src/screens/build.rs | 32 +++++- src/screens/inventory.rs | 55 +++++++++ src/screens/mod.rs | 38 ++++++- src/types.rs | 2 +- 7 files changed, 124 insertions(+), 265 deletions(-) delete mode 100644 src/screens/# create mode 100644 src/screens/inventory.rs diff --git a/src/blocks.rs b/src/blocks.rs index 4af3a95..2531452 100644 --- a/src/blocks.rs +++ b/src/blocks.rs @@ -2,6 +2,7 @@ use macroquad::prelude::*; use crate::textures::AssetStore; use crate::types::Direction; +#[derive(Eq, Hash, Clone, PartialEq)] pub enum Block { Dirt(Direction), GrassCenter(Direction) diff --git a/src/main.rs b/src/main.rs index 78f6eba..565bd85 100644 --- a/src/main.rs +++ b/src/main.rs @@ -10,34 +10,15 @@ use types::{ GameEvent }; use textures::AssetStore; -use screens::welcome::WelcomeScreen; -use screens::build::BuildScreen; +use screens::Screen; -enum Screen { - Welcome(WelcomeScreen), - Build(BuildScreen) -} -impl GameComponent for Screen { - fn draw(&self, assets: &AssetStore) { - match self { - Screen::Welcome(w) => w.draw(&assets), - Screen::Build(b) => b.draw(&assets) - } - } - fn ev_loop(&mut self) -> GameEvent { - match self { - Screen::Welcome(w) => w.ev_loop(), - Screen::Build(b) => b.ev_loop() - } - } -} #[macroquad::main("Little Town")] async fn main() { let assets = AssetStore::init().await; - let mut screen = Screen::Welcome(WelcomeScreen::new()); + let mut screen = Screen::default(); loop { clear_background(Color::from_rgba(215, 189, 165, 255)); diff --git a/src/screens/# b/src/screens/# deleted file mode 100644 index 6c7b2c6..0000000 --- a/src/screens/# +++ /dev/null @@ -1,238 +0,0 @@ -use macroquad::prelude::*; -use std::collections::HashMap; -use crate::textures::AssetStore; -use crate::types::{ - GameComponent, - GameEvent, - Pos3 -}; -use crate::blocks::Block; - -struct Camera { - center: Vec2, - scale: f32 -} -impl Camera { - fn new() -> Self { - Self { - center: Vec2::new(0.0, 0.0), - scale: 1.0 - } - } -} - -/// image width -const TEXTURE_WIDTH: f32 = 256.0; -/// actual width inside ob cube -const TEXTURE_INNER_WIDTH: f32 = 223.0; // 216 -/// height of image -const TEXTURE_HEIGHT: f32 = 352.0; -/// empty space above texture -const TEXTURE_Y_WHITESPACE: f32 = 130.0; -/// actual height of cube -const TEXTURE_INNER_HEIGHT: f32 = 108.0; // 110 -/// height of top surface -const TEXTURE_DEPTH: f32 = 100.0; - -pub struct BuildScreen { - grid: HashMap, - cam: Camera, - mouse_down: bool -} -impl BuildScreen { - pub fn new() -> Self { - let mut this = Self { - grid: HashMap::new(), - cam: Camera::new(), - mouse_down: false - }; - - this.grid.insert(Pos3::new(0, 0, 0), Block::Dirt(crate::types::Direction::North)); - this.grid.insert(Pos3::new(1, 0, 0), Block::Dirt(crate::types::Direction::North)); - this.grid.insert(Pos3::new(2, 0, 0), Block::Dirt(crate::types::Direction::North)); - this.grid.insert(Pos3::new(2, 1, 0), Block::Dirt(crate::types::Direction::North)); - this.grid.insert(Pos3::new(2, 1, 1), Block::Dirt(crate::types::Direction::North)); - - this - } -} - -fn get_screen_coords(pos: &Pos3, scale: f32, center: Vec2) -> (f32, f32) { - let w_i = TEXTURE_INNER_WIDTH * scale; - let width = TEXTURE_WIDTH * scale; - let height = TEXTURE_HEIGHT * scale; - let h_i = TEXTURE_INNER_HEIGHT * scale; - - let dx = pos.y - pos.x; - let dy = pos.y + pos.x; - - let x = screen_width() / 2.0 - + dx as f32 * w_i / 2.0 - + center.x - - width / 2.0; - let y = screen_height() / 2.0 - + dy as f32 * h_i / 2.0 - - pos.z as f32 * h_i - + center.y - - height / 2.0; - - return (x,y); -} - -/// A block's face -/// /'\ -/// / A \ -/// |\ /| -/// | \./ | -/// \ B|C | -/// \.|./ -/// A - Top -/// B- Left -/// C -Right -enum Face { - Top, - Left, - Right -} -impl Face { - /// gets the face (if any) that was clicked - /// coordinates have to be normalized, - /// the top left should be (0,0) - fn from_xy(x: f32, y: f32) -> Option { - - // test B face - { - let ox = (TEXTURE_WIDTH / 2.0 - x).abs(); - let oy = (TEXTURE_Y_WHITESPACE + TEXTURE_DEPTH / 2.0 - y).abs(); - - let y_max = TEXTURE_DEPTH / 2.0; - let x_max = TEXTURE_WIDTH / 2.0; - - let grow = (0.0 - y_max)/(x_max - 0.0); - let cy = grow * ox + y_max; - - if cy <= oy { - return Some(Face::Top); - } - - } - - None - } -} - -impl GameComponent for BuildScreen { - fn draw(&self, assets: &AssetStore) { - // order: x (inc) -> y (inc) -> z (inc) - let mut render_order: Vec<(&Pos3, &Block)> = self.grid.iter().collect(); - render_order.sort_by_key(|(pos, _)| pos.x + pos.y*2 + pos.z*3 ); - - for (pos, block) in render_order.iter() { - let texture = block.get_texture(&assets); - let width = TEXTURE_WIDTH * self.cam.scale; - let height = TEXTURE_HEIGHT * self.cam.scale; - - let (x,y) = get_screen_coords(pos, self.cam.scale, self.cam.center); - - if x >= -width && x <= screen_width() - && y >= -width && y <= screen_height() { - // render block - draw_texture_ex( - texture, - x, - y, - WHITE, - DrawTextureParams { - dest_size: Some(Vec2::new(width, height)), - source: None, - rotation: 0.0, - flip_x: false, - flip_y: false, - pivot: Some(Vec2::new(width / 2.0, height / 2.0)) - }); - } - } - } - fn ev_loop(&mut self) -> GameEvent { - // mouse input - if is_mouse_button_down(MouseButton::Left) { - // currently holding button down - self.mouse_down = true; - } else if self.mouse_down { - // button was released - self.mouse_down = false; - // determine which block / side was clicked - let (mx, my) = mouse_position(); - - // virtual render cycle - let render_order: Vec<(&Pos3, &Block)> = self.grid.iter().collect(); - // no need to sort the first time - //render_order.sort_by_key(|(pos, _)| pos.x + pos.y*2 + pos.z*3 ); - - // list of positions in render que for given pixel - // (mx, my) - let mut in_path:Vec<&Pos3> = Vec::new(); - - for (pos, _) in render_order.iter() { - let (x,y) = get_screen_coords(pos, self.cam.scale, self.cam.center); - - if mx >= x - && mx <= x + TEXTURE_WIDTH - && my >= y + TEXTURE_Y_WHITESPACE - && my <= y + TEXTURE_HEIGHT { - - // check if mouse is above transparent area - // and skip block if necessary - if Face::from_xy(mx-x, my-y).is_none() { - println!("skipping"); - continue; - } - - // block in mouse path - in_path.push(pos); - } - } - in_path.sort_by_key(|pos| pos.x + pos.y*2 + pos.z*3 ); - if let Some(pos) = in_path.last() { - // position of clicked block - // because it is the last block in de render queue - // for a given pixel - let pos = Pos3::new(pos.x, pos.y, pos.z); - let (x,y) = get_screen_coords(&pos, self.cam.scale, self.cam.center); - let face = Face::from_xy(mx-x, my-y); - println!("{:?}", face); - - // TODO: determine side - self.grid.insert(pos, Block::GrassCenter(crate::types::Direction::West)); - } - } - - // zoom with Ctrl-MouseWheel - if is_key_down(KeyCode::LeftControl) { - let mut scale = self.cam.scale; - let (_, wy) = mouse_wheel(); - - scale += wy as f32 * 1.0/10.0; - - if scale > 0.05 && scale < 6.0 { - self.cam.scale = scale; - } - } - - // keyboard control - if is_key_down(KeyCode::Down) { - self.cam.center.y += 1.0 * (1.0/self.cam.scale); - } - if is_key_down(KeyCode::Up) { - self.cam.center.y -= 1.0 * (1.0/self.cam.scale); - } - if is_key_down(KeyCode::Left) { - self.cam.center.x -= 1.0 * (1.0/self.cam.scale); - } - if is_key_down(KeyCode::Right) { - self.cam.center.x += 1.0 * (1.0/self.cam.scale); - } - - GameEvent::None - } -} diff --git a/src/screens/build.rs b/src/screens/build.rs index bd36891..8d11930 100644 --- a/src/screens/build.rs +++ b/src/screens/build.rs @@ -7,12 +7,17 @@ use crate::types::{ Pos3 }; use crate::blocks::Block; +use super::inventory::Inventory; +/// the game camera struct Camera { + /// the centered pixel center: Vec2, + /// scales the texture scale: f32 } impl Camera { + /// initialize new camera fn new() -> Self { Self { center: Vec2::new(0.0, 0.0), @@ -37,14 +42,18 @@ const TEXTURE_DEPTH: f32 = 100.0; pub struct BuildScreen { grid: HashMap, cam: Camera, - mouse_down: bool + mouse_down: bool, + show_inv: bool, + inv: Inventory } impl BuildScreen { pub fn new() -> Self { let mut this = Self { grid: HashMap::new(), cam: Camera::new(), - mouse_down: false + mouse_down: false, + show_inv: false, + inv: Inventory::new() }; this.grid.insert(Pos3::new(0, 0, 0), Block::Dirt(crate::types::Direction::North)); @@ -145,6 +154,10 @@ impl Face { impl GameComponent for BuildScreen { fn draw(&self, assets: &AssetStore) { + if self.show_inv { + // TODO draw inventory + return; + } // order: x (inc) -> y (inc) -> z (inc) let mut render_order: Vec<(&Pos3, &Block)> = self.grid.iter().collect(); render_order.sort_by_key(|(pos, _)| pos.x + pos.y*2 + pos.z*3 ); @@ -234,7 +247,10 @@ impl GameComponent for BuildScreen { } } - self.grid.insert(pos, Block::GrassCenter(crate::types::Direction::West)); + if let Some(block) = self.inv.place() { + self.grid.insert(pos, block); + } + } } @@ -264,6 +280,16 @@ impl GameComponent for BuildScreen { self.cam.center.x += 1.0 * (1.0/self.cam.scale); } + if is_key_down(KeyCode::I) { + self.show_inv = true; + match self.inv.ev_loop() { + GameEvent::Quit => { + self.show_inv = false; + } + _ => () + } + } + GameEvent::None } } diff --git a/src/screens/inventory.rs b/src/screens/inventory.rs new file mode 100644 index 0000000..55d372e --- /dev/null +++ b/src/screens/inventory.rs @@ -0,0 +1,55 @@ +use macroquad::prelude::*; +use crate::types::{ + GameComponent, + GameEvent +}; +use crate::textures::AssetStore; +use crate::blocks::Block; +use std::collections::HashMap; + +pub struct Inventory { + /// when set to true, the player has an infinite amount of items + infinite_items: bool, + /// items in inventory + /// with their appropriate amount + /// if amount is zero, the item should be removed + /// if infinite_items is true, the amount wont decrease + contents: HashMap, + /// which block is currently selected + pub selected: Option +} +impl Inventory { + pub fn new() -> Self { + Self { + infinite_items: true, + contents: HashMap::new(), + selected: None + } + } + pub fn place(&mut self) -> Option { + if let Some(block) = &self.selected { + + if !self.infinite_items { + let cv: &usize = self.contents.get(&block).unwrap_or(&0); + + if cv > &0 { + *self.contents.get_mut(&block).unwrap_or(&mut 0) -= 1; + } else { + self.contents.remove(&block); + return None; + } + } + + return Some(block.clone()); + } + + return None; + } +} +impl GameComponent for Inventory { + fn draw(&self, assets: &AssetStore) { + } + fn ev_loop(&mut self) -> GameEvent { + GameEvent::None + } +} diff --git a/src/screens/mod.rs b/src/screens/mod.rs index 65c9b53..3a3e255 100644 --- a/src/screens/mod.rs +++ b/src/screens/mod.rs @@ -1,2 +1,36 @@ -pub mod welcome; -pub mod build; +mod welcome; +mod build; +mod inventory; + +use welcome::WelcomeScreen; +use build::BuildScreen; + +use crate::types::{ + GameComponent, + GameEvent +}; +use crate::textures::AssetStore; + +pub enum Screen { + Welcome(WelcomeScreen), + Build(BuildScreen), +} +impl GameComponent for Screen { + fn draw(&self, assets: &AssetStore) { + match self { + Screen::Welcome(w) => w.draw(&assets), + Screen::Build(b) => b.draw(&assets), + } + } + fn ev_loop(&mut self) -> GameEvent { + match self { + Screen::Welcome(w) => w.ev_loop(), + Screen::Build(b) => b.ev_loop(), + } + } +} +impl Default for Screen { + fn default() -> Self { + Self::Welcome(WelcomeScreen::new()) + } +} diff --git a/src/types.rs b/src/types.rs index 423d742..5ac73df 100644 --- a/src/types.rs +++ b/src/types.rs @@ -25,7 +25,7 @@ impl Pos3 { } /// Directions -#[derive(PartialEq)] +#[derive(Eq, Hash, Clone, PartialEq)] pub enum Direction { /// Left /// (left edge of screen) -- 2.38.5