use std::fmt::{self}; use egui_sfml::{egui, SfEgui}; use gamedebug_core::imm_dbg; use sfml::{ graphics::{Color, RenderTarget, RenderWindow}, window::{Event, Key}, }; use crate::{ debug::DebugState, game::GameState, graphics::{self, NATIVE_RESOLUTION}, input::KbInput, math::{wp_to_tp, WorldPos}, res::Res, }; /// Application level state (includes game and ui state, etc.) pub struct App { pub rw: RenderWindow, pub should_quit: bool, pub game: GameState, pub res: Res, pub sf_egui: SfEgui, pub kb_input: KbInput, pub debug: DebugState, } impl App { pub fn new() -> anyhow::Result { let rw = graphics::make_window(); let sf_egui = SfEgui::new(&rw); Ok(Self { rw, should_quit: false, game: GameState::default(), res: Res::load()?, sf_egui, kb_input: KbInput::default(), debug: DebugState::default(), }) } pub fn do_game_loop(&mut self) { while !self.should_quit { self.do_event_handling(); self.do_update(); self.do_rendering(); self.kb_input.clear_pressed(); gamedebug_core::inc_frame(); } } fn do_event_handling(&mut self) { while let Some(ev) = self.rw.poll_event() { self.sf_egui.add_event(&ev); self.kb_input.update_from_event(&ev); match ev { Event::Closed => self.should_quit = true, _ => {} } } } fn do_update(&mut self) { self.debug.update(&self.kb_input); if self.debug.freecam { self.do_freecam(); } else { let spd = if self.kb_input.down(Key::LShift) { 16.0 } else if self.kb_input.down(Key::LControl) { 256.0 } else { 4.0 }; if self.kb_input.down(Key::Left) { self.game.player.col_en.move_x(-spd, |_, _| false); } if self.kb_input.down(Key::Right) { self.game.player.col_en.move_x(spd, |_, _| false); } if self.kb_input.down(Key::Up) { self.game.player.col_en.move_y(-spd, |_, _| false); } if self.kb_input.down(Key::Down) { self.game.player.col_en.move_y(spd, |_, _| false); } let (x, y, _w, _h) = self.game.player.col_en.en.xywh(); self.game.camera_offset.x = (x - NATIVE_RESOLUTION.w as i32 / 2) as u32; self.game.camera_offset.y = (y - NATIVE_RESOLUTION.h as i32 / 2) as u32; } } fn do_freecam(&mut self) { let spd = if self.kb_input.down(Key::LShift) { 100 } else if self.kb_input.down(Key::LControl) { 1000 } else { 2 }; if self.kb_input.down(Key::Left) { self.game.camera_offset.x = self.game.camera_offset.x.saturating_sub(spd); } if self.kb_input.down(Key::Right) { self.game.camera_offset.x = self.game.camera_offset.x.saturating_add(spd); } if self.kb_input.down(Key::Up) { self.game.camera_offset.y = self.game.camera_offset.y.saturating_sub(spd); } if self.kb_input.down(Key::Down) { self.game.camera_offset.y = self.game.camera_offset.y.saturating_add(spd); } } fn do_rendering(&mut self) { self.rw.clear(Color::rgb(55, 221, 231)); self.game.draw_world(&mut self.rw, &self.res); self.game.draw_entities(&mut self.rw); self.sf_egui .do_frame(|ctx| { if self.debug.panel { debug_panel_ui(&mut self.debug, &mut self.game, ctx); } }) .unwrap(); self.sf_egui.draw(&mut self.rw, None); self.rw.display(); } } fn debug_panel_ui(debug: &mut DebugState, game: &mut GameState, ctx: &egui::Context) { egui::Window::new("Debug (F12)").show(ctx, |ui| { ui.label("Cam x"); ui.add(egui::DragValue::new(&mut game.camera_offset.x)); ui.label("Cam y"); ui.add(egui::DragValue::new(&mut game.camera_offset.y)); if debug.freecam { let tp = game.camera_offset.tile_pos(); imm_dbg!(tp); ui.label(format!( "Cam Depth: {}", LengthDisp(tp.y as i64 - wp_to_tp(WorldPos::SURFACE) as i64) )); ui.label(format!( "Cam offset from center: {}", LengthDisp(tp.x as i64 - wp_to_tp(WorldPos::CENTER) as i64) )); } else { let tp = game.player.center_tp(); imm_dbg!(tp); ui.label(format!( "Player Depth: {}", LengthDisp(tp.y as i64 - wp_to_tp(WorldPos::SURFACE) as i64) )); ui.label(format!( "Player offset from center: {}", LengthDisp(tp.x as i64 - wp_to_tp(WorldPos::CENTER) as i64) )); } ui.separator(); egui::ScrollArea::vertical().show(ui, |ui| { gamedebug_core::for_each_imm(|info| match info { gamedebug_core::Info::Msg(msg) => { ui.label(msg); } gamedebug_core::Info::Rect(_, _, _, _, _) => todo!(), }); }); gamedebug_core::clear_immediates(); }); } struct LengthDisp(i64); impl fmt::Display for LengthDisp { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let km = self.0 / 1000; let m = self.0 % 1000; write!(f, "{km} km, {m} m") } }