Console, experimental tile graphic for continuous tiles

This commit is contained in:
crumblingstatue 2023-04-16 01:03:12 +02:00
parent 8ee0c9d535
commit 4dfb0ff7d7
12 changed files with 201 additions and 23 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 568 B

After

Width:  |  Height:  |  Size: 962 B

Before After
Before After

View file

@ -13,6 +13,7 @@ use sfml::{
}; };
use crate::{ use crate::{
command::{Cmd, CmdVec},
debug::{self, DebugState}, debug::{self, DebugState},
game::{for_each_tile_on_screen, Biome, GameState}, game::{for_each_tile_on_screen, Biome, GameState},
graphics::{self, ScreenSc, ScreenVec}, graphics::{self, ScreenSc, ScreenVec},
@ -39,6 +40,7 @@ pub struct App {
/// Light map overlay, blended together with the non-lighted version of the scene /// Light map overlay, blended together with the non-lighted version of the scene
pub light_map: RenderTexture, pub light_map: RenderTexture,
pub project_dirs: ProjectDirs, pub project_dirs: ProjectDirs,
pub cmdvec: CmdVec,
} }
impl App { impl App {
@ -69,6 +71,7 @@ impl App {
rt, rt,
light_map, light_map,
project_dirs, project_dirs,
cmdvec: CmdVec::default(),
}) })
} }
@ -87,7 +90,14 @@ impl App {
fn do_event_handling(&mut self) { fn do_event_handling(&mut self) {
while let Some(ev) = self.rw.poll_event() { while let Some(ev) = self.rw.poll_event() {
self.sf_egui.add_event(&ev); self.sf_egui.add_event(&ev);
self.input.update_from_event(&ev); {
let ctx = self.sf_egui.context();
self.input.update_from_event(
&ev,
ctx.wants_keyboard_input(),
ctx.wants_pointer_input(),
);
}
match ev { match ev {
Event::Closed => self.should_quit = true, Event::Closed => self.should_quit = true,
Event::Resized { width, height } => { 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)); let view = View::from_rect(Rect::new(0., 0., width as f32, height as f32));
self.rw.set_view(&view); 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) { fn do_update(&mut self) {
self.debug.update(&self.input);
let rt_size = self.rt.size(); let rt_size = self.rt.size();
if self.debug.freecam { if self.debug.freecam {
self.do_freecam(); self.do_freecam();
@ -246,9 +263,21 @@ impl App {
let t = self.game.world.tile_at_mut(mouse_tpos, &self.game.worldgen); let t = self.game.world.tile_at_mut(mouse_tpos, &self.game.worldgen);
match &def.use_action { match &def.use_action {
UseAction::PlaceTile { layer, id } => match layer { UseAction::PlaceTile { layer, id } => match layer {
TileLayer::Bg => t.bg = *id, TileLayer::Bg => {
TileLayer::Mid => t.mid = *id, if t.bg == 0 {
TileLayer::Fg => t.fg = *id, 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 { UseAction::RemoveTile { layer } => match layer {
TileLayer::Bg => t.bg = 0, TileLayer::Bg => t.bg = 0,
@ -340,10 +369,10 @@ impl App {
&mut self.game, &mut self.game,
&mut self.res, &mut self.res,
&mut self.scale, &mut self.scale,
&mut self.cmdvec,
); );
}) })
.unwrap(); .unwrap();
self.sf_egui.draw(&mut self.rw, None);
if self.debug.show_atlas { if self.debug.show_atlas {
let atlas = &self.res.atlas.tex; let atlas = &self.res.atlas.tex;
let size = atlas.size(); let size = atlas.size();
@ -352,7 +381,31 @@ impl App {
self.rw.draw(&rs); self.rw.draw(&rs);
self.rw.draw(&Sprite::with_texture(atlas)); self.rw.draw(&Sprite::with_texture(atlas));
} }
self.sf_egui.draw(&mut self.rw, None);
self.rw.display(); 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()
}
}
}
} }
} }

54
src/cmdline.rs Normal file
View file

@ -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<Self> {
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),
}
}
}

15
src/command.rs Normal file
View file

@ -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<Cmd>;

View file

@ -1,9 +1,12 @@
use std::fmt::Write;
use egui_inspect::{derive::Inspect, inspect}; use egui_inspect::{derive::Inspect, inspect};
use sfml::{audio::SoundSource, window::Key}; use sfml::audio::SoundSource;
use crate::{ use crate::{
cmdline::CmdLine,
command::CmdVec,
game::GameState, game::GameState,
input::Input,
math::{px_per_frame_to_km_h, WorldPos}, math::{px_per_frame_to_km_h, WorldPos},
res::Res, res::Res,
stringfmt::LengthDisp, stringfmt::LengthDisp,
@ -13,21 +16,19 @@ use crate::{
#[derive(Default, Debug, Inspect)] #[derive(Default, Debug, Inspect)]
pub struct DebugState { pub struct DebugState {
panel: bool, pub panel: bool,
pub freecam: bool, pub freecam: bool,
tiledb_edit: bool, pub tiledb_edit: bool,
pub show_atlas: bool, pub show_atlas: bool,
pub console: Console,
} }
impl DebugState { #[derive(Default, Debug, Inspect)]
pub fn update(&mut self, input: &Input) { pub struct Console {
if input.pressed(Key::F12) { pub show: bool,
self.panel ^= true; pub cmdline: String,
} pub log: String,
if input.pressed(Key::F10) { pub just_opened: bool,
self.freecam ^= true;
}
}
} }
fn debug_panel_ui( fn debug_panel_ui(
@ -112,6 +113,7 @@ pub(crate) fn do_debug_ui(
game: &mut GameState, game: &mut GameState,
res: &mut Res, res: &mut Res,
scale: &mut u8, scale: &mut u8,
cmd: &mut CmdVec,
) { ) {
if debug.panel { if debug.panel {
debug_panel_ui(debug, game, ctx, res, scale); debug_panel_ui(debug, game, ctx, res, scale);
@ -119,4 +121,39 @@ pub(crate) fn do_debug_ui(
if debug.tiledb_edit { if debug.tiledb_edit {
tiledb_edit_ui(ctx, &mut game.tile_db); 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;
} }

View file

@ -38,6 +38,7 @@ pub struct GameState {
pub inventory: Inventory, pub inventory: Inventory,
pub itemdb: ItemDb, pub itemdb: ItemDb,
pub selected_inv_slot: usize, pub selected_inv_slot: usize,
pub spawn_point: WorldPos,
} }
#[derive(Debug, Inspect)] #[derive(Debug, Inspect)]
@ -182,6 +183,7 @@ impl GameState {
inventory: Inventory::new_debug(), inventory: Inventory::new_debug(),
itemdb: ItemDb::default(), itemdb: ItemDb::default(),
selected_inv_slot: 0, selected_inv_slot: 0,
spawn_point,
} }
} }
} }

View file

@ -14,7 +14,7 @@ pub struct Input {
} }
impl 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 { match ev {
&Event::KeyPressed { code, .. } => { &Event::KeyPressed { code, .. } => {
self.pressed.insert(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 /// Pressed event should be cleared every frame
pub fn clear_pressed(&mut self) { pub fn clear_pressed(&mut self) {

View file

@ -1,5 +1,7 @@
mod app; mod app;
mod bitmanip; mod bitmanip;
mod cmdline;
mod command;
mod debug; mod debug;
mod game; mod game;
mod graphics; mod graphics;

View file

@ -50,6 +50,13 @@ impl WorldPos {
x: Self::CENTER, x: Self::CENTER,
y: Self::SURFACE, 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 { pub fn wp_to_tp(wp: WPosSc) -> TPosSc {

View file

@ -16,8 +16,8 @@ pub struct AtlasBundle {
impl AtlasBundle { impl AtlasBundle {
pub fn new() -> anyhow::Result<Self> { pub fn new() -> anyhow::Result<Self> {
let cfg = TexturePackerConfig { let cfg = TexturePackerConfig {
max_width: 4096, max_width: 512,
max_height: 4096, max_height: 512,
allow_rotation: false, allow_rotation: false,
border_padding: 0, border_padding: 0,
texture_padding: 0, texture_padding: 0,
@ -65,7 +65,6 @@ fn make_pix_buf(packer: &TexturePacker<image::DynamicImage, String>) -> Vec<u8>
let (w, h) = (packer.width(), packer.height()); let (w, h) = (packer.width(), packer.height());
let px_size = 4; let px_size = 4;
let mut vec = vec![0; w as usize * h as usize * px_size as usize]; let mut vec = vec![0; w as usize * h as usize * px_size as usize];
dbg!(w, h);
for y in 0..h { for y in 0..h {
for x in 0..w { for x in 0..w {
let idx = ((y * w + x) * px_size) as usize; let idx = ((y * w + x) * px_size) as usize;

BIN
tiles.dat

Binary file not shown.