From 4dfb0ff7d7b3bb8719f0c6b7e0973da83eb5e25d Mon Sep 17 00:00:00 2001 From: crumblingstatue Date: Sun, 16 Apr 2023 01:03:12 +0200 Subject: [PATCH] Console, experimental tile graphic for continuous tiles --- res/graphics/tiles/panzerium.png | Bin 0 -> 25269 bytes res/graphics/tiles/platform.png | Bin 568 -> 962 bytes src/app.rs | 65 ++++++++++++++++++++++++++++--- src/cmdline.rs | 54 +++++++++++++++++++++++++ src/command.rs | 15 +++++++ src/debug.rs | 63 +++++++++++++++++++++++------- src/game.rs | 2 + src/input.rs | 11 +++++- src/main.rs | 2 + src/math.rs | 7 ++++ src/texture_atlas.rs | 5 +-- tiles.dat | Bin 220 -> 220 bytes 12 files changed, 201 insertions(+), 23 deletions(-) create mode 100644 res/graphics/tiles/panzerium.png create mode 100644 src/cmdline.rs create mode 100644 src/command.rs diff --git a/res/graphics/tiles/panzerium.png b/res/graphics/tiles/panzerium.png new file mode 100644 index 0000000000000000000000000000000000000000..5d830013ce655efaee3ae47775c069198d1bd025 GIT binary patch literal 25269 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 C>@vat literal 0 HcmV?d00001 diff --git a/res/graphics/tiles/platform.png b/res/graphics/tiles/platform.png index ab06dbcd382db336f9d286122616d5543521c612..c9733eed8213d43797da695d1a3a5975c9e26052 100644 GIT binary patch delta 489 zcmdnNa)^Dy6UKT`E|CfAvJw~=825X+IEF+VetX4olZYcv%ftAf(D3s%V$4jl4=5V! z6f%FXC5E{va+jE=L;?4&&6iL2v|N5!V)gg^li%CdzdW7kI#VgaYWwY^-62Mayy^KT z7pqUdwnBA7(1)oqwHvmdn&EeQ>hXyor7FE5ipCloTSey`)||A)q<%{0O2uUw2bOKH z$xO59d+>I4o0r1FnDx>b4^z!qHbl)({=l&sHUJvQ_sD%3}jl} zbRuQVlJiF`WMm&Fs7;ym=g(EaIfirowFGHxsQA{GYrS#K?Yo?lP8=9ZmUL{8i>n4`O{?dOtk48v0SMMC?89C(cy? z8f*6Lcq70jb|{AJ<(p`u(7@R5oH6Z5kX?wyyA4JY_2svV2r5n5rRgHX zv0l$f<<9$qU$bobT6bSqrNp*YW52v#+NWQxmR3_HNgRskTxpQ@;ZxF|eU^)up6pM2 z%DE&#>cn&Z{LSU=9^dM1cRR~FYBD&jZR#kH=@V5|`v1&4x$4nr%e0{G3)>Do-g#rT z)1fXG(Q97orXP~%)U@gAoH@_Dz-q4Fa^ZT0UvWHvN+B)l7#J8BJYD@<);T3K0RS5N Bu+aBz}ClVF(4LY9XrItq(V y&ux;oV`A_K`_?sG%D~;9cg1rvc?O47{Ojvj^}b~a$}%u8FnGH9xvX self.should_quit = true, Event::Resized { width, height } => { @@ -100,13 +110,20 @@ impl App { let view = View::from_rect(Rect::new(0., 0., width as f32, height as f32)); self.rw.set_view(&view); } + Event::KeyPressed { code, .. } => match code { + Key::F11 => { + self.debug.console.show ^= true; + self.debug.console.just_opened = true; + } + Key::F12 => self.debug.panel ^= true, + _ => {} + }, _ => {} } } } fn do_update(&mut self) { - self.debug.update(&self.input); let rt_size = self.rt.size(); if self.debug.freecam { self.do_freecam(); @@ -246,9 +263,21 @@ impl App { let t = self.game.world.tile_at_mut(mouse_tpos, &self.game.worldgen); match &def.use_action { UseAction::PlaceTile { layer, id } => match layer { - TileLayer::Bg => t.bg = *id, - TileLayer::Mid => t.mid = *id, - TileLayer::Fg => t.fg = *id, + TileLayer::Bg => { + if t.bg == 0 { + t.bg = *id + } + } + TileLayer::Mid => { + if t.mid == 0 { + t.mid = *id + } + } + TileLayer::Fg => { + if t.fg == 0 { + t.fg = *id + } + } }, UseAction::RemoveTile { layer } => match layer { TileLayer::Bg => t.bg = 0, @@ -340,10 +369,10 @@ impl App { &mut self.game, &mut self.res, &mut self.scale, + &mut self.cmdvec, ); }) .unwrap(); - self.sf_egui.draw(&mut self.rw, None); if self.debug.show_atlas { let atlas = &self.res.atlas.tex; let size = atlas.size(); @@ -352,7 +381,31 @@ impl App { self.rw.draw(&rs); self.rw.draw(&Sprite::with_texture(atlas)); } + self.sf_egui.draw(&mut self.rw, None); self.rw.display(); + drop(spr); + self.execute_commands(); + } + + fn execute_commands(&mut self) { + for cmd in self.cmdvec.drain(..) { + match cmd { + Cmd::QuitApp => self.should_quit = true, + Cmd::ToggleFreecam => self.debug.freecam ^= true, + Cmd::TeleportPlayer { pos, relative } => { + if relative { + let s2dc = pos.to_s2dc(); + self.game.world.player.col_en.en.pos.x += s2dc.x; + self.game.world.player.col_en.en.pos.y += s2dc.y; + } else { + self.game.world.player.col_en.en.pos = pos.to_s2dc() + } + } + Cmd::TeleportPlayerSpawn => { + self.game.world.player.col_en.en.pos = self.game.spawn_point.to_s2dc() + } + } + } } } diff --git a/src/cmdline.rs b/src/cmdline.rs new file mode 100644 index 0000000..dcaae1e --- /dev/null +++ b/src/cmdline.rs @@ -0,0 +1,54 @@ +use clap::Parser; + +use crate::{command::Cmd, math::WorldPos}; + +#[derive(Parser)] +pub enum CmdLine { + Quit, + Freecam, + Clear, + Tp(Tp), + Spawn, +} + +#[derive(Parser)] +pub struct Tp { + x: u32, + y: u32, + /// Relative to current position + #[arg(short, long)] + rel: bool, +} +impl Tp { + fn to_world_pos(&self) -> WorldPos { + WorldPos { + x: self.x, + y: self.y, + } + } +} + +pub enum Dispatch { + Cmd(Cmd), + ClearConsole, +} + +impl CmdLine { + pub fn parse_cmdline(cmdline: &str) -> anyhow::Result { + let words = std::iter::once(" ").chain(cmdline.split_whitespace()); + Ok(Self::try_parse_from(words)?) + } + + pub(crate) fn dispatch(&self) -> Dispatch { + match self { + CmdLine::Quit => Dispatch::Cmd(Cmd::QuitApp), + CmdLine::Freecam => Dispatch::Cmd(Cmd::ToggleFreecam), + CmdLine::Clear => Dispatch::ClearConsole, + CmdLine::Tp(tp) => Dispatch::Cmd(Cmd::TeleportPlayer { + pos: tp.to_world_pos(), + relative: tp.rel, + }), + CmdLine::Spawn => Dispatch::Cmd(Cmd::TeleportPlayerSpawn), + } + } +} diff --git a/src/command.rs b/src/command.rs new file mode 100644 index 0000000..5972422 --- /dev/null +++ b/src/command.rs @@ -0,0 +1,15 @@ +use crate::math::WorldPos; + +/// A command that can change application or game state +pub enum Cmd { + /// Quit the application + QuitApp, + ToggleFreecam, + TeleportPlayer { + pos: WorldPos, + relative: bool, + }, + TeleportPlayerSpawn, +} + +pub type CmdVec = Vec; diff --git a/src/debug.rs b/src/debug.rs index 1ad62b1..c9e32a2 100644 --- a/src/debug.rs +++ b/src/debug.rs @@ -1,9 +1,12 @@ +use std::fmt::Write; + use egui_inspect::{derive::Inspect, inspect}; -use sfml::{audio::SoundSource, window::Key}; +use sfml::audio::SoundSource; use crate::{ + cmdline::CmdLine, + command::CmdVec, game::GameState, - input::Input, math::{px_per_frame_to_km_h, WorldPos}, res::Res, stringfmt::LengthDisp, @@ -13,21 +16,19 @@ use crate::{ #[derive(Default, Debug, Inspect)] pub struct DebugState { - panel: bool, + pub panel: bool, pub freecam: bool, - tiledb_edit: bool, + pub tiledb_edit: bool, pub show_atlas: bool, + pub console: Console, } -impl DebugState { - pub fn update(&mut self, input: &Input) { - if input.pressed(Key::F12) { - self.panel ^= true; - } - if input.pressed(Key::F10) { - self.freecam ^= true; - } - } +#[derive(Default, Debug, Inspect)] +pub struct Console { + pub show: bool, + pub cmdline: String, + pub log: String, + pub just_opened: bool, } fn debug_panel_ui( @@ -112,6 +113,7 @@ pub(crate) fn do_debug_ui( game: &mut GameState, res: &mut Res, scale: &mut u8, + cmd: &mut CmdVec, ) { if debug.panel { debug_panel_ui(debug, game, ctx, res, scale); @@ -119,4 +121,39 @@ pub(crate) fn do_debug_ui( if debug.tiledb_edit { tiledb_edit_ui(ctx, &mut game.tile_db); } + if debug.console.show { + console_ui(ctx, debug, cmd); + } +} + +fn console_ui(ctx: &egui::Context, debug: &mut DebugState, cmd: &mut CmdVec) { + egui::Window::new("Console (F11)").show(ctx, |ui| { + let re = + ui.add(egui::TextEdit::singleline(&mut debug.console.cmdline).hint_text("Command")); + if debug.console.just_opened { + re.request_focus(); + } + if re.lost_focus() && ui.input(|inp| inp.key_pressed(egui::Key::Enter)) { + re.request_focus(); + let cmdline = match CmdLine::parse_cmdline(&debug.console.cmdline) { + Ok(cmd) => cmd, + Err(e) => { + writeln!(&mut debug.console.log, "{e}").unwrap(); + debug.console.cmdline.clear(); + return; + } + }; + debug.console.cmdline.clear(); + match cmdline.dispatch() { + crate::cmdline::Dispatch::Cmd(command) => cmd.push(command), + crate::cmdline::Dispatch::ClearConsole => debug.console.log.clear(), + } + } + egui::ScrollArea::vertical() + .stick_to_bottom(true) + .show(ui, |ui| { + ui.add(egui::TextEdit::multiline(&mut &debug.console.log[..])); + }); + }); + debug.console.just_opened = false; } diff --git a/src/game.rs b/src/game.rs index 81789e0..5d39a50 100644 --- a/src/game.rs +++ b/src/game.rs @@ -38,6 +38,7 @@ pub struct GameState { pub inventory: Inventory, pub itemdb: ItemDb, pub selected_inv_slot: usize, + pub spawn_point: WorldPos, } #[derive(Debug, Inspect)] @@ -182,6 +183,7 @@ impl GameState { inventory: Inventory::new_debug(), itemdb: ItemDb::default(), selected_inv_slot: 0, + spawn_point, } } } diff --git a/src/input.rs b/src/input.rs index 4f65191..c2bf7c1 100644 --- a/src/input.rs +++ b/src/input.rs @@ -14,7 +14,7 @@ pub struct Input { } impl Input { - pub fn update_from_event(&mut self, ev: &Event) { + pub fn update_from_event(&mut self, ev: &Event, egui_kbd: bool, egui_ptr: bool) { match ev { &Event::KeyPressed { code, .. } => { self.pressed.insert(code); @@ -52,6 +52,15 @@ impl Input { } _ => {} } + if egui_kbd { + self.pressed.clear(); + self.down.clear(); + } + if egui_ptr { + self.lmb_down = false; + self.rmb_down = false; + self.mid_pressed = false; + } } /// Pressed event should be cleared every frame pub fn clear_pressed(&mut self) { diff --git a/src/main.rs b/src/main.rs index b6fa0d1..c9f45fa 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,7 @@ mod app; mod bitmanip; +mod cmdline; +mod command; mod debug; mod game; mod graphics; diff --git a/src/math.rs b/src/math.rs index c91dd79..2f9edd4 100644 --- a/src/math.rs +++ b/src/math.rs @@ -50,6 +50,13 @@ impl WorldPos { x: Self::CENTER, y: Self::SURFACE, }; + + pub(crate) fn to_s2dc(self) -> s2dc::Vec2 { + s2dc::Vec2 { + x: self.x as i32, + y: self.y as i32, + } + } } pub fn wp_to_tp(wp: WPosSc) -> TPosSc { diff --git a/src/texture_atlas.rs b/src/texture_atlas.rs index 0c2551e..514c94b 100644 --- a/src/texture_atlas.rs +++ b/src/texture_atlas.rs @@ -16,8 +16,8 @@ pub struct AtlasBundle { impl AtlasBundle { pub fn new() -> anyhow::Result { let cfg = TexturePackerConfig { - max_width: 4096, - max_height: 4096, + max_width: 512, + max_height: 512, allow_rotation: false, border_padding: 0, texture_padding: 0, @@ -65,7 +65,6 @@ fn make_pix_buf(packer: &TexturePacker) -> Vec let (w, h) = (packer.width(), packer.height()); let px_size = 4; let mut vec = vec![0; w as usize * h as usize * px_size as usize]; - dbg!(w, h); for y in 0..h { for x in 0..w { let idx = ((y * w + x) * px_size) as usize; diff --git a/tiles.dat b/tiles.dat index f42778ff49e3f641140df6b6a0b6ccee8ece22c6..d3897fae8229b4f756cfa2b63c71687239ff0253 100644 GIT binary patch delta 16 Ycmcb^c!zPqBu2K0lU-TvGbktk05w$wZ~y=R delta 16 Ycmcb^c!zPqBu3_mlU-R(GAJkj05swSR{#J2