diff --git a/src/entity.rs b/src/entity.rs index b938164..68313db 100644 --- a/src/entity.rs +++ b/src/entity.rs @@ -1,13 +1,10 @@ use ggez::{Context, GameResult}; -use crate::engine_constants::EngineConstants; -use crate::game_state::GameState; -use crate::GameContext; +use crate::frame::Frame; +use crate::SharedGameState; pub trait GameEntity { - fn init(&mut self, _state: &GameState, _game_ctx: &mut GameContext, _ctx: &mut Context) -> GameResult { Ok(()) } + fn tick(&mut self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult; - fn tick(&mut self, state: &GameState, constants: &EngineConstants, ctx: &mut Context) -> GameResult; - - fn draw(&self, state: &GameState, game_ctx: &mut GameContext, ctx: &mut Context) -> GameResult; + fn draw(&self, state: &mut SharedGameState, ctx: &mut Context, frame: &Frame) -> GameResult; } diff --git a/src/frame.rs b/src/frame.rs index b8f22a5..f5a75a4 100644 --- a/src/frame.rs +++ b/src/frame.rs @@ -1,5 +1,6 @@ use crate::player::Player; use crate::stage::Stage; +use crate::SharedGameState; pub struct Frame { pub x: isize, @@ -8,32 +9,32 @@ pub struct Frame { } impl Frame { - pub fn update(&mut self, player: &Player, stage: &Stage, canvas_size: (f32, f32)) { - if (stage.map.width - 1) * 16 < canvas_size.0 as usize { - self.x = -(((canvas_size.0 as isize - ((stage.map.width - 1) * 16) as isize) * 0x200) / 2); + pub fn update(&mut self, state: &SharedGameState, player: &Player, stage: &Stage) { + if (stage.map.width - 1) * 16 < state.canvas_size.0 as usize { + self.x = -(((state.canvas_size.0 as isize - ((stage.map.width - 1) * 16) as isize) * 0x200) / 2); } else { - self.x += (player.target_x - (canvas_size.0 as isize * 0x200 / 2) - self.x) / self.wait; + self.x += (player.target_x - (state.canvas_size.0 as isize * 0x200 / 2) - self.x) / self.wait; if self.x < 0 { self.x = 0; } - let max_x = (((stage.map.width as isize - 1) * 16) - canvas_size.0 as isize) * 0x200; + let max_x = (((stage.map.width as isize - 1) * 16) - state.canvas_size.0 as isize) * 0x200; if self.x > max_x { self.x = max_x; } } - if (stage.map.height - 1) * 16 < canvas_size.1 as usize { - self.y = -(((canvas_size.1 as isize - ((stage.map.height - 1) * 16) as isize) * 0x200) / 2); + if (stage.map.height - 1) * 16 < state.canvas_size.1 as usize { + self.y = -(((state.canvas_size.1 as isize - ((stage.map.height - 1) * 16) as isize) * 0x200) / 2); } else { - self.y += (player.target_y - (canvas_size.1 as isize * 0x200 / 2) - self.y) / self.wait; + self.y += (player.target_y - (state.canvas_size.1 as isize * 0x200 / 2) - self.y) / self.wait; if self.y < 0 { self.y = 0; } - let max_y = (((stage.map.height as isize - 1) * 16) - canvas_size.1 as isize) * 0x200; + let max_y = (((stage.map.height as isize - 1) * 16) - state.canvas_size.1 as isize) * 0x200; if self.y > max_y { self.y = max_y; } diff --git a/src/game_state.rs b/src/game_state.rs deleted file mode 100644 index dcd2eb1..0000000 --- a/src/game_state.rs +++ /dev/null @@ -1,101 +0,0 @@ -use ggez::{Context, GameResult}; -use log::info; - -use crate::bitfield; -use crate::entity::GameEntity; -use crate::frame::Frame; -use crate::GameContext; -use crate::player::Player; -use crate::scene::game_scene::GameScene; -use crate::stage::Stage; - -bitfield! { - pub struct KeyState(u16); - impl Debug; - pub left, set_left: 0; - pub right, set_right: 1; - pub up, set_up: 2; - pub down, set_down: 3; - pub map, set_map: 4; - pub jump, set_jump: 5; - pub fire, set_fire: 6; - pub weapon_next, set_weapon_next: 7; - pub weapon_prev, set_weapon_prev: 8; -} - -bitfield! { - pub struct GameFlags(u32); - impl Debug; - pub flag_x01, set_flag_x01: 0; - pub control_enabled, set_control_enabled: 1; - pub flag_x04, set_flag_x04: 2; -} - -pub struct GameState { - pub tick: usize, - pub stage: Stage, - pub frame: Frame, - pub flags: GameFlags, - pub key_state: KeyState, - pub key_trigger: KeyState, - player: Player, - key_old: u16, -} - -impl GameState { - pub fn new(game_ctx: &mut GameContext, ctx: &mut Context) -> GameResult { - Ok(Self { - tick: 0, - stage: Stage::empty(), - player: Player::new(&game_ctx.constants, ctx)?, - frame: Frame { - x: 0, - y: 0, - wait: 16, - }, - flags: GameFlags(0), - key_state: KeyState(0), - key_trigger: KeyState(0), - key_old: 0, - }) - } - - pub fn player(&self) -> &Player { - &self.player - } - - pub fn player_mut(&mut self) -> &mut Player { - &mut self.player - } - - pub fn update_key_trigger(&mut self) { - let trigger = self.key_state.0 & (self.key_state.0 ^ self.key_old); - self.key_old = self.key_state.0; - self.key_trigger = KeyState(trigger); - } - - pub fn switch_to_stage(&mut self, id: usize, game_ctx: &mut GameContext, ctx: &mut Context) -> GameResult { - let stage = Stage::load(ctx, &game_ctx.base_path, &game_ctx.stages[id])?; - info!("Loaded stage: {}", stage.data.name); - info!("Map size: {}x{}", stage.map.width, stage.map.height); - - game_ctx.next_scene = Some(Box::new(GameScene::new(self, game_ctx, ctx)?)); - self.stage = stage; - - Ok(()) - } - - pub fn init(&mut self, game_ctx: &mut GameContext, ctx: &mut Context) -> GameResult { - self.tick = 0; - self.player = Player::new(&game_ctx.constants, ctx)?; - - self.player.x = 700 * 0x200; - self.player.y = 1000 * 0x200; - - self.flags.set_flag_x01(true); - self.flags.set_control_enabled(true); - - //game_ctx.sound_manager.play_song(ctx)?; - Ok(()) - } -} diff --git a/src/live_debugger.rs b/src/live_debugger.rs index 355bd7a..e4f4b38 100644 --- a/src/live_debugger.rs +++ b/src/live_debugger.rs @@ -1,36 +1,82 @@ use ggez::{Context, GameResult}; -use imgui::{Condition, im_str, Window}; +use imgui::{Condition, im_str, ImStr, ImString, Window}; +use itertools::Itertools; -use crate::game_state::GameState; -use crate::GameContext; +use crate::scene::game_scene::GameScene; +use crate::SharedGameState; pub struct LiveDebugger { selected_item: i32, + stages: Vec, + error: Option, } impl LiveDebugger { pub fn new() -> Self { Self { - selected_item: 0, + selected_item: -1, + stages: vec![], + error: None, } } - pub fn run(&mut self, state: &mut GameState, game_ctx: &GameContext, ctx: &mut Context, ui: &mut imgui::Ui) -> GameResult { - Window::new(im_str!("Live Debugger")) + pub fn run_ingame(&mut self, game_scene: &mut GameScene, state: &mut SharedGameState, ctx: &mut Context, ui: &mut imgui::Ui) -> GameResult { + /*Window::new(im_str!("Live Debugger")) .size([300.0, 100.0], Condition::FirstUseEver) .build(ui, || { ui.text(format!( "Player position: ({:.1},{:.1})", - state.player().x as f32 / 512.0, - state.player().y as f32 / 512.0, + state.player.x as f32 / 512.0, + state.player.y as f32 / 512.0, )); - }); + });*/ - Window::new(im_str!("Stages")) - .size([240.0, 320.0], Condition::FirstUseEver) + if self.error.is_some() { + Window::new(im_str!("Error!")) + .resizable(false) + .collapsible(false) + .size([300.0, 100.0], Condition::Always) + .build(ui, || { + ui.push_item_width(-1.0); + ui.text(self.error.as_ref().unwrap()); + + if ui.button(im_str!("OK"), [0.0, 0.0]) { + self.error = None; + } + }); + } + + Window::new(im_str!("Map selector")) + .collapsed(true, Condition::FirstUseEver) + .size([240.0, 270.0], Condition::FirstUseEver) .build(ui, || { - ui.list_box(im_str!("Stage table"), &mut self.selected_item, - &[im_str!("Null"), im_str!("Egg Corridor")], 10); + if self.stages.is_empty() { + for s in state.stages.iter() { + self.stages.push(ImString::new(s.name.to_owned())); + } + + self.selected_item = match state.stages.iter().find_position(|s| s.name == game_scene.stage.data.name) { + Some((pos, _)) => { pos as i32 } + _ => { -1 } + }; + } + let stages: Vec<&ImStr> = self.stages.iter().map(|e| e.as_ref()).collect(); + + ui.push_item_width(-1.0); + ui.list_box(im_str!(""), &mut self.selected_item, &stages, 10); + + if ui.button(im_str!("Load"), [0.0, 0.0]) { + match GameScene::new(state, ctx, self.selected_item as usize) { + Ok(mut scene) => { + scene.player.x = (scene.stage.map.width / 2 * 16 * 0x200) as isize; + scene.player.y = (scene.stage.map.height / 2 * 16 * 0x200) as isize; + state.next_scene = Some(Box::new(scene)); + } + Err(e) => { + self.error = Some(ImString::new(e.to_string())); + } + } + } }); Ok(()) diff --git a/src/main.rs b/src/main.rs index 162cec3..d3b579f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,8 +7,7 @@ use std::path; use ggez::{Context, ContextBuilder, event, filesystem, GameResult}; use ggez::conf::{WindowMode, WindowSetup}; -use ggez::event::KeyCode; -use ggez::event::winit_event::{ElementState, Event, KeyboardInput, WindowEvent}; +use ggez::event::{KeyCode, KeyMods}; use ggez::graphics; use ggez::graphics::DrawParam; use ggez::input::keyboard; @@ -16,17 +15,14 @@ use ggez::mint::ColumnMatrix4; use ggez::nalgebra::Vector2; use log::*; use pretty_env_logger::env_logger::Env; +use winit::{ElementState, Event, KeyboardInput, WindowEvent}; use crate::engine_constants::EngineConstants; -use crate::entity::GameEntity; -use crate::game_state::GameState; -use crate::game_state::KeyState; use crate::live_debugger::LiveDebugger; -use crate::scene::game_scene::GameScene; use crate::scene::loading_scene::LoadingScene; use crate::scene::Scene; use crate::sound::SoundManager; -use crate::stage::{Stage, StageData}; +use crate::stage::StageData; use crate::texture_set::TextureSet; use crate::ui::UI; @@ -35,7 +31,6 @@ mod engine_constants; mod entity; mod enemy; mod frame; -mod game_state; mod live_debugger; mod map; mod player; @@ -47,16 +42,41 @@ mod text_script; mod texture_set; mod ui; +bitfield! { + pub struct KeyState(u16); + impl Debug; + left, set_left: 0; + right, set_right: 1; + up, set_up: 2; + down, set_down: 3; + map, set_map: 4; + jump, set_jump: 5; + fire, set_fire: 6; + weapon_next, set_weapon_next: 7; + weapon_prev, set_weapon_prev: 8; +} + +bitfield! { + pub struct GameFlags(u32); + impl Debug; + pub flag_x01, set_flag_x01: 0; + pub control_enabled, set_control_enabled: 1; + pub flag_x04, set_flag_x04: 2; +} + struct Game { scene: Option>, - state: Option, - ctx: GameContext, + state: SharedGameState, + debugger: LiveDebugger, ui: UI, scaled_matrix: ColumnMatrix4, def_matrix: ColumnMatrix4, } -pub struct GameContext { +pub struct SharedGameState { + pub flags: GameFlags, + pub key_state: KeyState, + pub key_trigger: KeyState, pub texture_set: TextureSet, pub base_path: String, pub stages: Vec, @@ -66,6 +86,16 @@ pub struct GameContext { pub canvas_size: (f32, f32), pub screen_size: (f32, f32), pub next_scene: Option>, + key_old: u16, +} + +impl SharedGameState { + pub fn update_key_trigger(&mut self) { + let mut trigger = self.key_state.0 ^ self.key_old; + trigger = self.key_state.0 & trigger; + self.key_old = self.key_state.0; + self.key_trigger = KeyState(trigger); + } } impl Game { @@ -88,8 +118,16 @@ impl Game { let s = Game { scene: None, - state: None, - ctx: GameContext { + scaled_matrix: DrawParam::new() + .scale(Vector2::new(scale, scale)) + .to_matrix(), + debugger: LiveDebugger::new(), + ui: UI::new(ctx)?, + def_matrix: DrawParam::new().to_matrix(), + state: SharedGameState { + flags: GameFlags(0), + key_state: KeyState(0), + key_trigger: KeyState(0), texture_set: TextureSet::new(base_path), base_path: str!(base_path), stages: Vec::new(), @@ -99,24 +137,16 @@ impl Game { screen_size, canvas_size, next_scene: None, + key_old: 0, }, - ui: UI::new(ctx)?, - scaled_matrix: DrawParam::new() - .scale(Vector2::new(scale, scale)) - .to_matrix(), - def_matrix: DrawParam::new().to_matrix(), }; Ok(s) } fn update(&mut self, ctx: &mut Context) -> GameResult { - if self.state.is_none() { - self.state = Some(GameState::new(&mut self.ctx, ctx)?); - } - - if self.scene.is_some() && self.state.is_some() { - self.scene.as_mut().unwrap().tick(self.state.as_mut().unwrap(), &mut self.ctx, ctx)?; + if self.scene.is_some() { + self.scene.as_mut().unwrap().tick(&mut self.state, ctx)?; } Ok(()) } @@ -126,52 +156,49 @@ impl Game { graphics::set_transform(ctx, self.scaled_matrix); graphics::apply_transformations(ctx)?; - if let (Some(scene), Some(state)) = (self.scene.as_mut(), self.state.as_mut()) { - scene.draw(state, &mut self.ctx, ctx)?; + if self.scene.is_some() { + self.scene.as_ref().unwrap().draw(&mut self.state, ctx)?; graphics::set_transform(ctx, self.def_matrix); graphics::apply_transformations(ctx)?; - - self.ui.draw(state, &mut self.ctx, ctx, scene)?; + self.ui.draw(&mut self.debugger, &mut self.state, ctx, self.scene.as_mut().unwrap())?; } graphics::present(ctx)?; Ok(()) } - fn key_down_event(&mut self, _ctx: &mut Context, key_code: KeyCode, repeat: bool) { + fn key_down_event(&mut self, _ctx: &mut Context, key_code: KeyCode, _key_mod: KeyMods, repeat: bool) { if repeat { return; } // todo: proper keymaps? - if let Some(state) = self.state.as_mut() { - match key_code { - KeyCode::Left => { state.key_state.set_left(true) } - KeyCode::Right => { state.key_state.set_right(true) } - KeyCode::Up => { state.key_state.set_up(true) } - KeyCode::Down => { state.key_state.set_down(true) } - KeyCode::Z => { state.key_state.set_jump(true) } - KeyCode::X => { state.key_state.set_fire(true) } - KeyCode::A => { state.key_state.set_weapon_prev(true) } - KeyCode::S => { state.key_state.set_weapon_next(true) } - _ => {} - } + let state = &mut self.state; + match key_code { + KeyCode::Left => { state.key_state.set_left(true) } + KeyCode::Right => { state.key_state.set_right(true) } + KeyCode::Up => { state.key_state.set_up(true) } + KeyCode::Down => { state.key_state.set_down(true) } + KeyCode::Z => { state.key_state.set_jump(true) } + KeyCode::X => { state.key_state.set_fire(true) } + KeyCode::A => { state.key_state.set_weapon_prev(true) } + KeyCode::S => { state.key_state.set_weapon_next(true) } + _ => {} } } - fn key_up_event(&mut self, _ctx: &mut Context, key_code: KeyCode) { - if let Some(state) = self.state.as_mut() { - match key_code { - KeyCode::Left => { state.key_state.set_left(false) } - KeyCode::Right => { state.key_state.set_right(false) } - KeyCode::Up => { state.key_state.set_up(false) } - KeyCode::Down => { state.key_state.set_down(false) } - KeyCode::Z => { state.key_state.set_jump(false) } - KeyCode::X => { state.key_state.set_fire(false) } - KeyCode::A => { state.key_state.set_weapon_prev(false) } - KeyCode::S => { state.key_state.set_weapon_next(false) } - _ => {} - } + fn key_up_event(&mut self, _ctx: &mut Context, key_code: KeyCode, _key_mod: KeyMods) { + let state = &mut self.state; + match key_code { + KeyCode::Left => { state.key_state.set_left(false) } + KeyCode::Right => { state.key_state.set_right(false) } + KeyCode::Up => { state.key_state.set_up(false) } + KeyCode::Down => { state.key_state.set_down(false) } + KeyCode::Z => { state.key_state.set_jump(false) } + KeyCode::X => { state.key_state.set_fire(false) } + KeyCode::A => { state.key_state.set_weapon_prev(false) } + KeyCode::S => { state.key_state.set_weapon_next(false) } + _ => {} } } } @@ -197,7 +224,7 @@ pub fn main() -> GameResult { let (ctx, event_loop) = &mut cb.build()?; let game = &mut Game::new(ctx)?; - game.ctx.next_scene = Some(Box::new(LoadingScene::new())); + game.state.next_scene = Some(Box::new(LoadingScene::new())); while ctx.continuing { ctx.timer_context.tick(); @@ -209,20 +236,22 @@ pub fn main() -> GameResult { Event::WindowEvent { event, .. } => match event { WindowEvent::CloseRequested => event::quit(ctx), WindowEvent::KeyboardInput { - input: KeyboardInput { + input: + KeyboardInput { + state: el_state, virtual_keycode: Some(keycode), - state: input_state, + modifiers, .. }, .. } => { - match input_state { + match el_state { ElementState::Pressed => { let repeat = keyboard::is_key_repeated(ctx); - game.key_down_event(ctx, keycode, repeat); + game.key_down_event(ctx, keycode, modifiers.into(), repeat); } ElementState::Released => { - game.key_up_event(ctx, keycode); + game.key_up_event(ctx, keycode, modifiers.into()); } } } @@ -235,10 +264,11 @@ pub fn main() -> GameResult { game.update(ctx)?; game.draw(ctx)?; - if game.ctx.next_scene.is_some() && game.state.is_some() { - mem::swap(&mut game.scene, &mut game.ctx.next_scene); - game.ctx.next_scene = None; - game.scene.as_mut().unwrap().init(game.state.as_mut().unwrap(), &mut game.ctx, ctx)?; + if game.state.next_scene.is_some() { + mem::swap(&mut game.scene, &mut game.state.next_scene); + game.state.next_scene = None; + + game.scene.as_mut().unwrap().init(&mut game.state, ctx)?; } } Ok(()) diff --git a/src/player.rs b/src/player.rs index 9c92aac..a034de1 100644 --- a/src/player.rs +++ b/src/player.rs @@ -3,10 +3,10 @@ use num_traits::clamp; use crate::bitfield; use crate::common::{Direction, Rect}; -use crate::engine_constants::{EngineConstants, PhysicsConsts}; +use crate::engine_constants::PhysicsConsts; use crate::entity::GameEntity; -use crate::game_state::GameState; -use crate::GameContext; +use crate::frame::Frame; +use crate::SharedGameState; use crate::str; bitfield! { @@ -103,8 +103,11 @@ pub struct Player { } impl Player { - pub fn new(constants: &EngineConstants, ctx: &mut Context) -> GameResult { + pub fn new(state: &mut SharedGameState, ctx: &mut Context) -> GameResult { + let constants = &state.constants; + let tex_player_name = str!("MyChar"); + Ok(Player { x: 0, y: 0, @@ -142,7 +145,7 @@ impl Player { }) } - fn tick_normal(&mut self, state: &GameState, constants: &EngineConstants) -> GameResult<()> { + fn tick_normal(&mut self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult<()> { if self.cond.cond_x02() { return Ok(()); } @@ -220,23 +223,23 @@ impl Player { if state.key_state.up() { self.boost_sw = 2; self.xm = 0; - self.ym = constants.booster.b2_0_up; + self.ym = state.constants.booster.b2_0_up; } else if state.key_state.left() { self.boost_sw = 2; self.xm = 0; - self.ym = constants.booster.b2_0_left; + self.ym = state.constants.booster.b2_0_left; } else if state.key_state.right() { self.boost_sw = 2; self.xm = 0; - self.ym = constants.booster.b2_0_right; + self.ym = state.constants.booster.b2_0_right; } else if state.key_state.down() { self.boost_sw = 2; self.xm = 0; - self.ym = constants.booster.b2_0_down; + self.ym = state.constants.booster.b2_0_down; } else { self.boost_sw = 2; self.xm = 0; - self.ym = constants.booster.b2_0_up_nokey; + self.ym = state.constants.booster.b2_0_up_nokey; } } } @@ -451,11 +454,11 @@ impl Player { Ok(()) } - fn tick_stream(&mut self, state: &GameState, constants: &EngineConstants) -> GameResult<()> { + fn tick_stream(&mut self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult<()> { Ok(()) } - fn tick_animation(&mut self, state: &GameState, constants: &EngineConstants) { + fn tick_animation(&mut self, state: &SharedGameState) { if self.cond.cond_x02() { return; } @@ -520,10 +523,10 @@ impl Player { match self.direction { Direction::Left => { - self.anim_rect = constants.my_char.animations_left[self.anim_num]; + self.anim_rect = state.constants.my_char.animations_left[self.anim_num]; } Direction::Right => { - self.anim_rect = constants.my_char.animations_right[self.anim_num]; + self.anim_rect = state.constants.my_char.animations_right[self.anim_num]; } _ => {} } @@ -533,12 +536,7 @@ impl Player { } impl GameEntity for Player { - fn init(&mut self, state: &GameState, game_ctx: &mut GameContext, ctx: &mut Context) -> GameResult { - game_ctx.texture_set.ensure_texture_loaded(ctx, &game_ctx.constants, &self.tex_player_name)?; - Ok(()) - } - - fn tick(&mut self, state: &GameState, constants: &EngineConstants, ctx: &mut Context) -> GameResult { + fn tick(&mut self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult<()> { if !self.cond.visible() { return Ok(()); } @@ -560,35 +558,33 @@ impl GameEntity for Player { // AirProcess(); // todo } - self.tick_normal(state, constants)?; + self.tick_normal(state, ctx)?; } 1 => { - self.tick_stream(state, constants)?; + self.tick_stream(state, ctx)?; } _ => {} } self.cond.set_cond_x20(false); - self.tick_animation(state, constants); + self.tick_animation(state); Ok(()) } - fn draw(&self, state: &GameState, game_ctx: &mut GameContext, ctx: &mut Context) -> GameResult { + fn draw(&self, state: &mut SharedGameState, ctx: &mut Context, frame: &Frame) -> GameResult<()> { if !self.cond.visible() || self.cond.cond_x02() { return Ok(()); } // todo draw weapon - - if let Some(batch) = game_ctx.texture_set.tex_map.get_mut(&self.tex_player_name) { - batch.add_rect( - (((self.x - self.view.left as isize) / 0x200) - (state.frame.x / 0x200)) as f32, - (((self.y - self.view.top as isize) / 0x200) - (state.frame.y / 0x200)) as f32, - &self.anim_rect, - ); - batch.draw(ctx)?; - } + let batch = state.texture_set.get_or_load_batch(ctx, &state.constants, &self.tex_player_name)?; + batch.add_rect( + (((self.x - self.view.left as isize) / 0x200) - (frame.x / 0x200)) as f32, + (((self.y - self.view.top as isize) / 0x200) - (frame.y / 0x200)) as f32, + &self.anim_rect, + ); + batch.draw(ctx)?; Ok(()) } diff --git a/src/player_hit.rs b/src/player_hit.rs index edbfcab..522765c 100644 --- a/src/player_hit.rs +++ b/src/player_hit.rs @@ -1,13 +1,14 @@ use num_traits::clamp; -use crate::game_state::GameState; use crate::player::Player; +use crate::stage::Stage; +use crate::SharedGameState; const OFF_X: &[isize; 4] = &[0, 1, 0, 1]; const OFF_Y: &[isize; 4] = &[0, 0, 1, 1]; impl Player { - fn judge_hit_block(&mut self, x: isize, y: isize, state: &GameState) { + fn judge_hit_block(&mut self, state: &SharedGameState, x: isize, y: isize) { // left wall if (self.y - self.hit.top as isize) < (y * 0x10 + 4) * 0x200 && self.y + self.hit.bottom as isize > (y * 0x10 - 4) * 0x200 @@ -81,7 +82,7 @@ impl Player { } } - fn judge_hit_triangle_a(&mut self, x: isize, y: isize) { + fn judge_hit_triangle_a(&mut self, state: &SharedGameState, x: isize, y: isize) { if self.x < (x * 0x10 + 8) * 0x200 && self.x > (x * 0x10 - 8) * 0x200 && (self.y - self.hit.top as isize) < (y * 0x10 * 0x200) - (self.x - x * 0x10 * 0x200) / 2 + 0x800 @@ -100,7 +101,7 @@ impl Player { } } - fn judge_hit_triangle_b(&mut self, x: isize, y: isize) { + fn judge_hit_triangle_b(&mut self, state: &SharedGameState, x: isize, y: isize) { if self.x < (x * 0x10 + 8) * 0x200 && self.x > (x * 0x10 - 8) * 0x200 && (self.y - self.hit.top as isize) < (y * 0x10 * 0x200) - (self.x - x * 0x10 * 0x200) / 2 - 0x800 @@ -119,7 +120,7 @@ impl Player { } } - fn judge_hit_triangle_c(&mut self, x: isize, y: isize) { + fn judge_hit_triangle_c(&mut self, state: &SharedGameState, x: isize, y: isize) { if self.x < (x * 0x10 + 8) * 0x200 && self.x > (x * 0x10 - 8) * 0x200 && (self.y - self.hit.top as isize) < (y * 0x10 * 0x200) + (self.x - x * 0x10 * 0x200) / 2 - 0x800 @@ -138,7 +139,7 @@ impl Player { } } - fn judge_hit_triangle_d(&mut self, x: isize, y: isize) { + fn judge_hit_triangle_d(&mut self, state: &SharedGameState, x: isize, y: isize) { if (self.x < (x * 0x10 + 8) * 0x200) && (self.x > (x * 0x10 - 8) * 0x200) && (self.y - self.hit.top as isize) < (y * 0x10 * 0x200) + (self.x - x * 0x10 * 0x200) / 2 + 0x800 @@ -157,7 +158,7 @@ impl Player { } } - fn judge_hit_triangle_e(&mut self, x: isize, y: isize) { + fn judge_hit_triangle_e(&mut self, state: &SharedGameState, x: isize, y: isize) { self.flags.set_flag_x10000(true); if (self.x < (x * 0x10 + 8) * 0x200) @@ -179,7 +180,7 @@ impl Player { } } - fn judge_hit_triangle_f(&mut self, x: isize, y: isize) { + fn judge_hit_triangle_f(&mut self, state: &SharedGameState, x: isize, y: isize) { self.flags.set_flag_x20000(true); if (self.x < (x * 0x10 + 8) * 0x200) @@ -201,7 +202,7 @@ impl Player { } } - fn judge_hit_triangle_g(&mut self, x: isize, y: isize) { + fn judge_hit_triangle_g(&mut self, state: &SharedGameState, x: isize, y: isize) { self.flags.set_flag_x40000(true); if (self.x < (x * 0x10 + 8) * 0x200) @@ -223,7 +224,7 @@ impl Player { } } - fn judge_hit_triangle_h(&mut self, x: isize, y: isize) { + fn judge_hit_triangle_h(&mut self, state: &SharedGameState, x: isize, y: isize) { self.flags.set_flag_x80000(true); if (self.x < (x * 0x10 + 8) * 0x200) @@ -245,7 +246,7 @@ impl Player { } } - fn judge_hit_water(&mut self, x: isize, y: isize) { + fn judge_hit_water(&mut self, state: &SharedGameState, x: isize, y: isize) { if (self.x - self.hit.right as isize) < (x * 0x10 + 5) * 0x200 && (self.x + self.hit.right as isize) > (x * 0x10 - 5) * 0x200 && (self.y - self.hit.top as isize) < (y * 0x10 + 5) * 0x200 @@ -254,55 +255,55 @@ impl Player { } } - pub fn tick_map_collisions(&mut self, state: &GameState) { - let x = clamp(self.x / 0x10 / 0x200, 0, state.stage.map.width as isize); - let y = clamp(self.y / 0x10 / 0x200, 0, state.stage.map.height as isize); + pub fn tick_map_collisions(&mut self, state: &SharedGameState, stage: &Stage) { + let x = clamp(self.x / 0x10 / 0x200, 0, stage.map.width as isize); + let y = clamp(self.y / 0x10 / 0x200, 0, stage.map.height as isize); for (ox, oy) in OFF_X.iter().zip(OFF_Y) { - let attrib = state.stage.map.get_attribute((x + *ox) as usize, (y + *oy) as usize); + let attrib = stage.map.get_attribute((x + *ox) as usize, (y + *oy) as usize); match attrib { // Block 0x02 | 0x60 => { - self.judge_hit_water(x + *ox, y + *oy); + self.judge_hit_water(state, x + *ox, y + *oy); } 0x05 | 0x41 | 0x43 | 0x46 => { - self.judge_hit_block(x + *ox, y + *oy, state); + self.judge_hit_block(state, x + *ox, y + *oy); } 0x50 | 0x70 => { - self.judge_hit_triangle_a(x + *ox, y + *oy); - if attrib & 0x20 != 0 { self.judge_hit_water(x + *ox, y + *oy); } + self.judge_hit_triangle_a(state, x + *ox, y + *oy); + if attrib & 0x20 != 0 { self.judge_hit_water(state, x + *ox, y + *oy); } } 0x51 | 0x71 => { - self.judge_hit_triangle_b(x + *ox, y + *oy); - if attrib & 0x20 != 0 { self.judge_hit_water(x + *ox, y + *oy); } + self.judge_hit_triangle_b(state, x + *ox, y + *oy); + if attrib & 0x20 != 0 { self.judge_hit_water(state, x + *ox, y + *oy); } } 0x52 | 0x72 => { - self.judge_hit_triangle_c(x + *ox, y + *oy); - if attrib & 0x20 != 0 { self.judge_hit_water(x + *ox, y + *oy); } + self.judge_hit_triangle_c(state, x + *ox, y + *oy); + if attrib & 0x20 != 0 { self.judge_hit_water(state, x + *ox, y + *oy); } } 0x53 | 0x73 => { - self.judge_hit_triangle_d(x + *ox, y + *oy); - if attrib & 0x20 != 0 { self.judge_hit_water(x + *ox, y + *oy); } + self.judge_hit_triangle_d(state, x + *ox, y + *oy); + if attrib & 0x20 != 0 { self.judge_hit_water(state, x + *ox, y + *oy); } } 0x54 | 0x74 => { - self.judge_hit_triangle_e(x + *ox, y + *oy); - if attrib & 0x20 != 0 { self.judge_hit_water(x + *ox, y + *oy); } + self.judge_hit_triangle_e(state, x + *ox, y + *oy); + if attrib & 0x20 != 0 { self.judge_hit_water(state, x + *ox, y + *oy); } } 0x55 | 0x75 => { - self.judge_hit_triangle_f(x + *ox, y + *oy); - if attrib & 0x20 != 0 { self.judge_hit_water(x + *ox, y + *oy); } + self.judge_hit_triangle_f(state, x + *ox, y + *oy); + if attrib & 0x20 != 0 { self.judge_hit_water(state, x + *ox, y + *oy); } } 0x56 | 0x76 => { - self.judge_hit_triangle_g(x + *ox, y + *oy); - if attrib & 0x20 != 0 { self.judge_hit_water(x + *ox, y + *oy); } + self.judge_hit_triangle_g(state, x + *ox, y + *oy); + if attrib & 0x20 != 0 { self.judge_hit_water(state, x + *ox, y + *oy); } } 0x57 | 0x77 => { - self.judge_hit_triangle_h(x + *ox, y + *oy); - if attrib & 0x20 != 0 { self.judge_hit_water(x + *ox, y + *oy); } + self.judge_hit_triangle_h(state, x + *ox, y + *oy); + if attrib & 0x20 != 0 { self.judge_hit_water(state, x + *ox, y + *oy); } } 0x61 => { - self.judge_hit_water(x + *ox, y + *oy); - self.judge_hit_block(x + *ox, y + *oy, state); + self.judge_hit_water(state, x + *ox, y + *oy); + self.judge_hit_block(state, x + *ox, y + *oy); } _ => {} } diff --git a/src/scene/game_scene.rs b/src/scene/game_scene.rs index 506da5d..a7528c5 100644 --- a/src/scene/game_scene.rs +++ b/src/scene/game_scene.rs @@ -1,18 +1,23 @@ use ggez::{Context, GameResult}; -use ggez::GameError::EventLoopError; use ggez::nalgebra::clamp; +use log::info; +use num_traits::abs; use crate::common::Rect; use crate::entity::GameEntity; -use crate::game_state::GameState; -use crate::GameContext; -use crate::scene::Scene; -use crate::stage::BackgroundType; -use crate::str; +use crate::frame::Frame; use crate::live_debugger::LiveDebugger; +use crate::player::Player; +use crate::scene::Scene; +use crate::SharedGameState; +use crate::stage::{BackgroundType, Stage}; +use crate::str; pub struct GameScene { - debugger: LiveDebugger, + pub tick: usize, + pub stage: Stage, + pub frame: Frame, + pub player: Player, tex_tileset_name: String, tex_background_name: String, tex_hud_name: String, @@ -34,17 +39,24 @@ pub enum Alignment { } impl GameScene { - pub fn new(state: &GameState, game_ctx: &mut GameContext, ctx: &mut Context) -> GameResult { - let tex_tileset_name = str!(["Stage/", &state.stage.data.tileset.filename()].join("")); - let tex_background_name = state.stage.data.background.filename(); + pub fn new(state: &mut SharedGameState, ctx: &mut Context, id: usize) -> GameResult { + let stage = Stage::load(ctx, &state.base_path, &state.stages[id])?; + info!("Loaded stage: {}", stage.data.name); + info!("Map size: {}x{}", stage.map.width, stage.map.height); + + let tex_tileset_name = ["Stage/", &stage.data.tileset.filename()].join(""); + let tex_background_name = stage.data.background.filename(); let tex_hud_name = str!("TextBox"); - game_ctx.texture_set.ensure_texture_loaded(ctx, &game_ctx.constants, &tex_tileset_name)?; - game_ctx.texture_set.ensure_texture_loaded(ctx, &game_ctx.constants, &tex_background_name)?; - game_ctx.texture_set.ensure_texture_loaded(ctx, &game_ctx.constants, &tex_hud_name)?; - Ok(Self { - debugger: LiveDebugger::new(), + tick: 0, + stage, + player: Player::new(state, ctx)?, + frame: Frame { + x: 0, + y: 0, + wait: 16, + }, tex_tileset_name, tex_background_name, tex_hud_name, @@ -53,13 +65,8 @@ impl GameScene { }) } - fn draw_number(&self, x: f32, y: f32, val: usize, align: Alignment, game_ctx: &mut GameContext, ctx: &mut Context) -> GameResult { - let set = game_ctx.texture_set.tex_map.get_mut(&self.tex_hud_name); - if set.is_none() { - return Ok(()); - } - - let batch = set.unwrap(); + fn draw_number(&self, x: f32, y: f32, val: usize, align: Alignment, state: &mut SharedGameState, ctx: &mut Context) -> GameResult { + let batch = state.texture_set.get_or_load_batch(ctx, &state.constants, &self.tex_hud_name)?; let n = val.to_string(); let align_offset = if align == Alignment::Right { n.len() as f32 * 8.0 } else { 0.0 }; @@ -72,13 +79,8 @@ impl GameScene { Ok(()) } - fn draw_hud(&self, state: &GameState, game_ctx: &mut GameContext, ctx: &mut Context) -> GameResult { - let set = game_ctx.texture_set.tex_map.get_mut(&self.tex_hud_name); - if set.is_none() { - return Ok(()); - } - let batch = set.unwrap(); - + fn draw_hud(&self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult { + let batch = state.texture_set.get_or_load_batch(ctx, &state.constants, &self.tex_hud_name)?; // todo: max ammo display // none @@ -98,30 +100,25 @@ impl GameScene { &Rect::::new_size(0, 40, 64, 8)); // bar batch.add_rect(40.0, 40.0, - &Rect::::new_size(0, 32, ((self.life_bar as usize * 40) / state.player().max_life as usize) - 1, 8)); + &Rect::::new_size(0, 32, ((self.life_bar as usize * 40) / self.player.max_life as usize) - 1, 8)); // life batch.add_rect(40.0, 40.0, - &Rect::::new_size(0, 24, ((state.player().life as usize * 40) / state.player().max_life as usize) - 1, 8)); + &Rect::::new_size(0, 24, ((self.player.life as usize * 40) / self.player.max_life as usize) - 1, 8)); batch.draw(ctx)?; - self.draw_number(40.0, 40.0, self.life_bar as usize, Alignment::Right, game_ctx, ctx)?; + self.draw_number(40.0, 40.0, self.life_bar as usize, Alignment::Right, state, ctx)?; Ok(()) } - fn draw_background(&self, state: &GameState, game_ctx: &mut GameContext, ctx: &mut Context) -> GameResult { - let set = game_ctx.texture_set.tex_map.get_mut(&self.tex_background_name); - if set.is_none() { - return Ok(()); - } + fn draw_background(&self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult { + let batch = state.texture_set.get_or_load_batch(ctx, &state.constants, &self.tex_background_name)?; - let batch = set.unwrap(); - - match state.stage.data.background_type { + match self.stage.data.background_type { BackgroundType::Stationary => { - let count_x = game_ctx.canvas_size.0 as usize / batch.width() + 1; - let count_y = game_ctx.canvas_size.1 as usize / batch.height() + 1; + let count_x = state.canvas_size.0 as usize / batch.width() + 1; + let count_y = state.canvas_size.1 as usize / batch.height() + 1; for y in 0..count_y { for x in 0..count_x { @@ -130,11 +127,11 @@ impl GameScene { } } BackgroundType::MoveDistant => { - let off_x = state.frame.x as usize / 2 % (batch.width() * 0x200); - let off_y = state.frame.y as usize / 2 % (batch.height() * 0x200); + let off_x = self.frame.x as usize / 2 % (batch.width() * 0x200); + let off_y = self.frame.y as usize / 2 % (batch.height() * 0x200); - let count_x = game_ctx.canvas_size.0 as usize / batch.width() + 2; - let count_y = game_ctx.canvas_size.1 as usize / batch.height() + 2; + let count_x = state.canvas_size.0 as usize / batch.width() + 2; + let count_y = state.canvas_size.1 as usize / batch.height() + 2; for y in 0..count_y { for x in 0..count_x { @@ -148,27 +145,27 @@ impl GameScene { BackgroundType::Black => {} BackgroundType::Autoscroll => {} BackgroundType::OutsideWind | BackgroundType::Outside => { - let offset = (state.tick % 640) as isize; + let offset = (self.tick % 640) as isize; - batch.add_rect(((game_ctx.canvas_size.0 - 320.0) / 2.0).floor(), 0.0, + batch.add_rect(((state.canvas_size.0 - 320.0) / 2.0).floor(), 0.0, &Rect::::new_size(0, 0, 320, 88)); - for x in ((-offset / 2)..(game_ctx.canvas_size.0 as isize)).step_by(320) { + for x in ((-offset / 2)..(state.canvas_size.0 as isize)).step_by(320) { batch.add_rect(x as f32, 88.0, &Rect::::new_size(0, 88, 320, 35)); } - for x in ((-offset % 320)..(game_ctx.canvas_size.0 as isize)).step_by(320) { + for x in ((-offset % 320)..(state.canvas_size.0 as isize)).step_by(320) { batch.add_rect(x as f32, 123.0, &Rect::::new_size(0, 123, 320, 23)); } - for x in ((-offset * 2)..(game_ctx.canvas_size.0 as isize)).step_by(320) { + for x in ((-offset * 2)..(state.canvas_size.0 as isize)).step_by(320) { batch.add_rect(x as f32, 146.0, &Rect::::new_size(0, 146, 320, 30)); } - for x in ((-offset * 4)..(game_ctx.canvas_size.0 as isize)).step_by(320) { + for x in ((-offset * 4)..(state.canvas_size.0 as isize)).step_by(320) { batch.add_rect(x as f32, 176.0, &Rect::::new_size(0, 176, 320, 64)); } @@ -180,76 +177,81 @@ impl GameScene { Ok(()) } - fn draw_tiles(&self, layer: TileLayer, state: &GameState, game_ctx: &mut GameContext, ctx: &mut Context) -> GameResult { - if let Some(batch) = game_ctx.texture_set.tex_map.get_mut(&self.tex_tileset_name) { - let mut rect = Rect::::new(0, 0, 16, 16); + fn draw_tiles(&self, state: &mut SharedGameState, ctx: &mut Context, layer: TileLayer) -> GameResult { + let batch = state.texture_set.get_or_load_batch(ctx, &state.constants, &self.tex_tileset_name)?; + let mut rect = Rect::::new(0, 0, 16, 16); - let tile_start_x = clamp(state.frame.x / 0x200 / 16, 0, state.stage.map.width as isize) as usize; - let tile_start_y = clamp(state.frame.y / 0x200 / 16, 0, state.stage.map.height as isize) as usize; - let tile_end_x = clamp((state.frame.x / 0x200 + 8 + game_ctx.canvas_size.0 as isize) / 16 + 1, 0, state.stage.map.width as isize) as usize; - let tile_end_y = clamp((state.frame.y / 0x200 + 8 + game_ctx.canvas_size.1 as isize) / 16 + 1, 0, state.stage.map.height as isize) as usize; + let tile_start_x = clamp(self.frame.x / 0x200 / 16, 0, self.stage.map.width as isize) as usize; + let tile_start_y = clamp(self.frame.y / 0x200 / 16, 0, self.stage.map.height as isize) as usize; + let tile_end_x = clamp((self.frame.x / 0x200 + 8 + state.canvas_size.0 as isize) / 16 + 1, 0, self.stage.map.width as isize) as usize; + let tile_end_y = clamp((self.frame.y / 0x200 + 8 + state.canvas_size.1 as isize) / 16 + 1, 0, self.stage.map.height as isize) as usize; - for y in tile_start_y..tile_end_y { - for x in tile_start_x..tile_end_x { - let tile = *state.stage.map.tiles - .get((y * state.stage.map.width) + x) - .unwrap(); + for y in tile_start_y..tile_end_y { + for x in tile_start_x..tile_end_x { + let tile = *self.stage.map.tiles + .get((y * self.stage.map.width) + x) + .unwrap(); - match layer { - TileLayer::Background => { - if state.stage.map.attrib[tile as usize] >= 0x20 { - continue; - } + match layer { + TileLayer::Background => { + if self.stage.map.attrib[tile as usize] >= 0x20 { + continue; } - TileLayer::Foreground => { - let attr = state.stage.map.attrib[tile as usize]; - if attr < 0x40 || attr >= 0x80 { - continue; - } - } - TileLayer::All => {} } - - rect.left = (tile as usize % 16) * 16; - rect.top = (tile as usize / 16) * 16; - rect.right = rect.left + 16; - rect.bottom = rect.top + 16; - - batch.add_rect((x as f32 * 16.0 - 8.0) - (state.frame.x / 0x200) as f32, (y as f32 * 16.0 - 8.0) - (state.frame.y / 0x200) as f32, &rect); + TileLayer::Foreground => { + let attr = self.stage.map.attrib[tile as usize]; + if attr < 0x40 || attr >= 0x80 { + continue; + } + } + _ => {} } - } - batch.draw(ctx)?; + rect.left = (tile as usize % 16) * 16; + rect.top = (tile as usize / 16) * 16; + rect.right = rect.left + 16; + rect.bottom = rect.top + 16; + + batch.add_rect((x as f32 * 16.0 - 8.0) - (self.frame.x / 0x200) as f32, (y as f32 * 16.0 - 8.0) - (self.frame.y / 0x200) as f32, &rect); + } } + + batch.draw(ctx)?; + Ok(()) } } impl Scene for GameScene { - fn init(&mut self, state: &mut GameState, game_ctx: &mut GameContext, ctx: &mut Context) -> GameResult { + fn init(&mut self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult { + state.sound_manager.play_song(ctx)?; + //self.player.x = 700 * 0x200; + //self.player.y = 1000 * 0x200; + //self.player.equip.set_booster_2_0(true); + state.flags.set_flag_x01(true); + state.flags.set_control_enabled(true); Ok(()) } - fn tick(&mut self, state: &mut GameState, game_ctx: &mut GameContext, ctx: &mut Context) -> GameResult { + fn tick(&mut self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult { state.update_key_trigger(); - /*if state.flags.flag_x01() { - state.player_mut().tick(state, &game_ctx.constants, ctx)?; - state.player_mut().flags.0 = 0; - state.player_mut().tick_map_collisions(state); - state.frame.update(state.player(), &state.stage, game_ctx.canvas_size); - }*/ + if state.flags.flag_x01() { + self.player.tick(state, ctx)?; - state.tick = state.tick.wrapping_add(1); - //state.tick(game_ctx, ctx)?; + self.player.flags.0 = 0; + self.player.tick_map_collisions(state, &self.stage); + + self.frame.update(state, &self.player, &self.stage); + } if state.flags.control_enabled() { // update health bar - if self.life_bar < state.player().life as usize { - self.life_bar = state.player().life as usize; + if self.life_bar < self.player.life as usize { + self.life_bar = self.player.life as usize; } - if self.life_bar > state.player().life as usize { + if self.life_bar > self.player.life as usize { self.life_bar_count += 1; if self.life_bar_count > 30 { self.life_bar -= 1; @@ -259,21 +261,25 @@ impl Scene for GameScene { } } + self.tick = self.tick.wrapping_add(1); Ok(()) } - fn draw(&self, state: &GameState, game_ctx: &mut GameContext, ctx: &mut Context) -> GameResult { - self.draw_background(state, game_ctx, ctx)?; - self.draw_tiles(TileLayer::Background, state, game_ctx, ctx)?; - state.player().draw(state, game_ctx, ctx)?; - self.draw_tiles(TileLayer::Foreground, state, game_ctx, ctx)?; - self.draw_hud(state, game_ctx, ctx)?; + fn draw(&self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult { + self.draw_background(state, ctx)?; + self.draw_tiles(state, ctx, TileLayer::Background)?; + self.player.draw(state, ctx, &self.frame)?; + self.draw_tiles(state, ctx, TileLayer::Foreground)?; + + self.draw_hud(state, ctx)?; + self.draw_number(16.0, 50.0, abs(self.player.x) as usize, Alignment::Left, state, ctx)?; + self.draw_number(16.0, 58.0, abs(self.player.y) as usize, Alignment::Left, state, ctx)?; Ok(()) } - fn overlay_draw(&mut self, state: &mut GameState, game_ctx: &mut GameContext, ctx: &mut Context, ui: &mut imgui::Ui) -> GameResult { - self.debugger.run(state, game_ctx, ctx, ui)?; + fn debug_overlay_draw(&mut self, dbg: &mut LiveDebugger, state: &mut SharedGameState, ctx: &mut Context, ui: &mut imgui::Ui) -> GameResult { + dbg.run_ingame(self, state, ctx, ui)?; Ok(()) } } diff --git a/src/scene/loading_scene.rs b/src/scene/loading_scene.rs index ab44757..7c65928 100644 --- a/src/scene/loading_scene.rs +++ b/src/scene/loading_scene.rs @@ -1,8 +1,8 @@ use ggez::{Context, GameResult}; -use crate::game_state::GameState; -use crate::GameContext; +use crate::scene::game_scene::GameScene; use crate::scene::Scene; +use crate::SharedGameState; use crate::stage::StageData; pub struct LoadingScene { @@ -18,35 +18,24 @@ impl LoadingScene { } impl Scene for LoadingScene { - fn init(&mut self, state: &mut GameState, game_ctx: &mut GameContext, ctx: &mut Context) -> GameResult { - game_ctx.texture_set.ensure_texture_loaded(ctx, &game_ctx.constants, "Loading")?; - Ok(()) - } - - fn tick(&mut self, state: &mut GameState, game_ctx: &mut GameContext, ctx: &mut Context) -> GameResult { + fn tick(&mut self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult { // deferred to let the loading image draw if self.tick == 1 { - let stages = StageData::load_stage_table(ctx, &game_ctx.base_path)?; - game_ctx.stages = stages; - } else if self.tick == 2 { - state.init(game_ctx, ctx)?; - state.switch_to_stage(53, game_ctx, ctx)?; + let stages = StageData::load_stage_table(ctx, &state.base_path)?; + state.stages = stages; + state.next_scene = Some(Box::new(GameScene::new(state, ctx, 53)?)); } self.tick += 1; Ok(()) } - fn draw(&self, state: &GameState, game_ctx: &mut GameContext, ctx: &mut Context) -> GameResult { - let loading = game_ctx.texture_set.tex_map.get_mut("Loading"); - - if loading.is_some() { - let img = loading.unwrap(); - img.add(((game_ctx.canvas_size.0 - img.width() as f32) / 2.0).floor(), - ((game_ctx.canvas_size.1 - img.height() as f32) / 2.0).floor()); - img.draw(ctx)?; - } + fn draw(&self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult { + let batch = state.texture_set.get_or_load_batch(ctx, &state.constants, "Loading")?; + batch.add(((state.canvas_size.0 - batch.width() as f32) / 2.0).floor(), + ((state.canvas_size.1 - batch.height() as f32) / 2.0).floor()); + batch.draw(ctx)?; Ok(()) } } diff --git a/src/scene/mod.rs b/src/scene/mod.rs index c8c2bed..0e966dc 100644 --- a/src/scene/mod.rs +++ b/src/scene/mod.rs @@ -1,17 +1,17 @@ use ggez::{Context, GameResult}; -use crate::GameContext; -use crate::game_state::GameState; +use crate::live_debugger::LiveDebugger; +use crate::SharedGameState; pub mod game_scene; pub mod loading_scene; pub trait Scene { - fn init(&mut self, _state: &mut GameState, _game_ctx: &mut GameContext, _ctx: &mut Context) -> GameResult { Ok(()) } + fn init(&mut self, _state: &mut SharedGameState, _ctx: &mut Context) -> GameResult { Ok(()) } - fn tick(&mut self, _state: &mut GameState, _game_ctx: &mut GameContext, _ctx: &mut Context) -> GameResult { Ok(()) } + fn tick(&mut self, _state: &mut SharedGameState, _ctx: &mut Context) -> GameResult { Ok(()) } - fn draw(&self, _state: &GameState, _game_ctx: &mut GameContext, _ctx: &mut Context) -> GameResult { Ok(()) } + fn draw(&self, _state: &mut SharedGameState, _ctx: &mut Context) -> GameResult { Ok(()) } - fn overlay_draw(&mut self, _state: &mut GameState, _game_ctx: &mut GameContext, _ctx: &mut Context, _ui: &mut imgui::Ui) -> GameResult { Ok(()) } + fn debug_overlay_draw(&mut self, dbg: &mut LiveDebugger, _state: &mut SharedGameState, _ctx: &mut Context, ui: &mut imgui::Ui) -> GameResult { Ok(()) } } diff --git a/src/sound/mod.rs b/src/sound/mod.rs index 015e060..02401b7 100644 --- a/src/sound/mod.rs +++ b/src/sound/mod.rs @@ -1,4 +1,4 @@ -use std::io::Cursor; +use std::io::{Cursor, Read}; use ggez::{Context, GameResult}; diff --git a/src/stage.rs b/src/stage.rs index 0bab6c5..444fab6 100644 --- a/src/stage.rs +++ b/src/stage.rs @@ -8,7 +8,6 @@ use ggez::GameError::ResourceLoadError; use log::info; use crate::map::Map; -use crate::str; #[derive(Debug, PartialEq, Eq, Hash)] pub struct NpcType { @@ -375,27 +374,6 @@ pub struct Stage { } impl Stage { - pub fn empty() -> Self { - Self { - map: Map { - attrib: [0u8; 256], - height: 16, - width: 16, - tiles: vec![0u8; 16 * 16], - }, - data: StageData { - map: str!("0"), - name: str!("Null"), - background: Background::new("bk0"), - background_type: BackgroundType::Black, - tileset: Tileset::new("0"), - boss_no: 0, - npc1: NpcType::new("0"), - npc2: NpcType::new("0"), - }, - } - } - pub fn load(ctx: &mut Context, root: &str, data: &StageData) -> GameResult { let map_file = filesystem::open(ctx, [root, "Stage/", &data.map, ".pxm"].join(""))?; let attrib_file = filesystem::open(ctx, [root, "Stage/", &data.tileset.name, ".pxa"].join(""))?; diff --git a/src/texture_set.rs b/src/texture_set.rs index 57b7d1f..e2bae09 100644 --- a/src/texture_set.rs +++ b/src/texture_set.rs @@ -147,14 +147,12 @@ impl TextureSet { }) } - pub fn ensure_texture_loaded(&mut self, ctx: &mut Context, constants: &EngineConstants, name: &str) -> GameResult { - if self.tex_map.contains_key(name) { - return Ok(()); + pub fn get_or_load_batch(&mut self, ctx: &mut Context, constants: &EngineConstants, name: &str) -> GameResult<&mut SizedBatch> { + if !self.tex_map.contains_key(name) { + let mut batch = self.load_texture(ctx, constants, name)?; + self.tex_map.insert(str!(name), batch); } - let batch = self.load_texture(ctx, constants, name)?; - self.tex_map.insert(str!(name), batch); - - Ok(()) + Ok(self.tex_map.get_mut(name).unwrap()) } } diff --git a/src/ui.rs b/src/ui.rs index 7c0078f..b6be47c 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -9,9 +9,9 @@ use imgui_gfx_renderer::gfx::handle::RenderTargetView; use imgui_gfx_renderer::gfx::memory::Typed; use imgui_winit_support::{HiDpiMode, WinitPlatform}; +use crate::live_debugger::LiveDebugger; use crate::scene::Scene; -use crate::GameContext; -use crate::game_state::GameState; +use crate::SharedGameState; mod types { pub type Device = gfx_device_gl::Device; @@ -36,7 +36,7 @@ impl UI { config: Some(FontConfig::default()), }, ]); - imgui.style_mut().use_dark_colors(); + imgui.style_mut().use_classic_colors(); let mut platform = WinitPlatform::init(&mut imgui); platform.attach_window(imgui.io_mut(), graphics::window(ctx), HiDpiMode::Rounded); @@ -78,7 +78,7 @@ impl UI { self.platform.handle_event(self.imgui.io_mut(), graphics::window(ctx), &event); } - pub fn draw(&mut self, state: &mut GameState, game_ctx: &mut GameContext, ctx: &mut Context, scene: &mut Box) -> GameResult { + pub fn draw(&mut self, dbg: &mut LiveDebugger, state: &mut SharedGameState, ctx: &mut Context, scene: &mut Box) -> GameResult { { let io = self.imgui.io_mut(); self.platform.prepare_frame(io, graphics::window(ctx)).map_err(|e| RenderError(e))?; @@ -88,7 +88,7 @@ impl UI { } let mut ui = self.imgui.frame(); - scene.overlay_draw(state, game_ctx, ctx, &mut ui)?; + scene.debug_overlay_draw(dbg, state, ctx, &mut ui)?; self.platform.prepare_render(&ui, graphics::window(ctx)); let draw_data = ui.render();