1
0
Fork 0
mirror of https://github.com/doukutsu-rs/doukutsu-rs synced 2025-11-26 14:17:08 +00:00

failed refactoring lol

This commit is contained in:
Alula 2020-08-19 13:21:40 +02:00
parent ff5962d97e
commit ccadb98a8a
No known key found for this signature in database
GPG key ID: 3E00485503A1D8BA
15 changed files with 518 additions and 289 deletions

View file

@ -10,9 +10,12 @@ panic = 'abort'
[dependencies] [dependencies]
byteorder = "1.3" byteorder = "1.3"
gfx_device_gl = "0.16"
ggez = { git = "https://github.com/ggez/ggez", rev = "4f4bdebff463881c36325c7e10520c9a4fd8f75c" } ggez = { git = "https://github.com/ggez/ggez", rev = "4f4bdebff463881c36325c7e10520c9a4fd8f75c" }
imgui = "0.4.0" imgui = "0.4.0"
imgui-ext = "0.3.0" imgui-ext = "0.3.0"
imgui-gfx-renderer = "0.4.0"
imgui-winit-support = {version = "0.4.0", default-features = false, features = ["winit-19"] }
image = {version = "0.22", default-features = false, features = ["png_codec", "pnm", "bmp"] } image = {version = "0.22", default-features = false, features = ["png_codec", "pnm", "bmp"] }
itertools = "0.9.0" itertools = "0.9.0"
lazy_static = "1.4.0" lazy_static = "1.4.0"
@ -25,3 +28,4 @@ rodio = { version = "0.11", default-features = false, features = ["flac", "vorbi
strum = "0.18.0" strum = "0.18.0"
strum_macros = "0.18.0" strum_macros = "0.18.0"
owning_ref = "0.4.1" owning_ref = "0.4.1"
winit = { version = "0.19.3" }

View file

@ -1,10 +1,13 @@
use ggez::{Context, GameResult}; use ggez::{Context, GameResult};
use crate::frame::Frame; use crate::engine_constants::EngineConstants;
use crate::SharedGameState; use crate::game_state::GameState;
use crate::GameContext;
pub trait GameEntity { pub trait GameEntity {
fn tick(&mut self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult; fn init(&mut self, _state: &GameState, _game_ctx: &mut GameContext, _ctx: &mut Context) -> GameResult { Ok(()) }
fn draw(&self, state: &mut SharedGameState, ctx: &mut Context, frame: &Frame) -> 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;
} }

View file

@ -1,6 +1,5 @@
use crate::player::Player; use crate::player::Player;
use crate::stage::Stage; use crate::stage::Stage;
use crate::SharedGameState;
pub struct Frame { pub struct Frame {
pub x: isize, pub x: isize,
@ -9,32 +8,32 @@ pub struct Frame {
} }
impl Frame { impl Frame {
pub fn update(&mut self, state: &SharedGameState, player: &Player, stage: &Stage) { pub fn update(&mut self, player: &Player, stage: &Stage, canvas_size: (f32, f32)) {
if (stage.map.width - 1) * 16 < state.canvas_size.0 as usize { if (stage.map.width - 1) * 16 < canvas_size.0 as usize {
self.x = -(((state.canvas_size.0 as isize - ((stage.map.width - 1) * 16) as isize) * 0x200) / 2); self.x = -(((canvas_size.0 as isize - ((stage.map.width - 1) * 16) as isize) * 0x200) / 2);
} else { } else {
self.x += (player.target_x - (state.canvas_size.0 as isize * 0x200 / 2) - self.x) / self.wait; self.x += (player.target_x - (canvas_size.0 as isize * 0x200 / 2) - self.x) / self.wait;
if self.x < 0 { if self.x < 0 {
self.x = 0; self.x = 0;
} }
let max_x = (((stage.map.width as isize - 1) * 16) - state.canvas_size.0 as isize) * 0x200; let max_x = (((stage.map.width as isize - 1) * 16) - canvas_size.0 as isize) * 0x200;
if self.x > max_x { if self.x > max_x {
self.x = max_x; self.x = max_x;
} }
} }
if (stage.map.height - 1) * 16 < state.canvas_size.1 as usize { if (stage.map.height - 1) * 16 < canvas_size.1 as usize {
self.y = -(((state.canvas_size.1 as isize - ((stage.map.height - 1) * 16) as isize) * 0x200) / 2); self.y = -(((canvas_size.1 as isize - ((stage.map.height - 1) * 16) as isize) * 0x200) / 2);
} else { } else {
self.y += (player.target_y - (state.canvas_size.1 as isize * 0x200 / 2) - self.y) / self.wait; self.y += (player.target_y - (canvas_size.1 as isize * 0x200 / 2) - self.y) / self.wait;
if self.y < 0 { if self.y < 0 {
self.y = 0; self.y = 0;
} }
let max_y = (((stage.map.height as isize - 1) * 16) - state.canvas_size.1 as isize) * 0x200; let max_y = (((stage.map.height as isize - 1) * 16) - canvas_size.1 as isize) * 0x200;
if self.y > max_y { if self.y > max_y {
self.y = max_y; self.y = max_y;
} }

101
src/game_state.rs Normal file
View file

@ -0,0 +1,101 @@
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<Self> {
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(())
}
}

38
src/live_debugger.rs Normal file
View file

@ -0,0 +1,38 @@
use ggez::{Context, GameResult};
use imgui::{Condition, im_str, Window};
use crate::game_state::GameState;
use crate::GameContext;
pub struct LiveDebugger {
selected_item: i32,
}
impl LiveDebugger {
pub fn new() -> Self {
Self {
selected_item: 0,
}
}
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"))
.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,
));
});
Window::new(im_str!("Stages"))
.size([240.0, 320.0], Condition::FirstUseEver)
.build(ui, || {
ui.list_box(im_str!("Stage table"), &mut self.selected_item,
&[im_str!("Null"), im_str!("Egg Corridor")], 10);
});
Ok(())
}
}

View file

@ -7,7 +7,7 @@ use std::path;
use ggez::{Context, ContextBuilder, event, filesystem, GameResult}; use ggez::{Context, ContextBuilder, event, filesystem, GameResult};
use ggez::conf::{WindowMode, WindowSetup}; use ggez::conf::{WindowMode, WindowSetup};
use ggez::event::{KeyCode, KeyMods}; use ggez::event::KeyCode;
use ggez::event::winit_event::{ElementState, Event, KeyboardInput, WindowEvent}; use ggez::event::winit_event::{ElementState, Event, KeyboardInput, WindowEvent};
use ggez::graphics; use ggez::graphics;
use ggez::graphics::DrawParam; use ggez::graphics::DrawParam;
@ -18,17 +18,25 @@ use log::*;
use pretty_env_logger::env_logger::Env; use pretty_env_logger::env_logger::Env;
use crate::engine_constants::EngineConstants; 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::loading_scene::LoadingScene;
use crate::scene::Scene; use crate::scene::Scene;
use crate::sound::SoundManager; use crate::sound::SoundManager;
use crate::stage::StageData; use crate::stage::{Stage, StageData};
use crate::texture_set::TextureSet; use crate::texture_set::TextureSet;
use crate::ui::UI;
mod common; mod common;
mod engine_constants; mod engine_constants;
mod entity; mod entity;
mod enemy; mod enemy;
mod frame; mod frame;
mod game_state;
mod live_debugger;
mod map; mod map;
mod player; mod player;
mod player_hit; mod player_hit;
@ -37,40 +45,18 @@ mod stage;
mod sound; mod sound;
mod text_script; mod text_script;
mod texture_set; 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 { struct Game {
scene: Option<Box<dyn Scene>>, scene: Option<Box<dyn Scene>>,
state: SharedGameState, state: Option<GameState>,
ctx: GameContext,
ui: UI,
scaled_matrix: ColumnMatrix4<f32>, scaled_matrix: ColumnMatrix4<f32>,
def_matrix: ColumnMatrix4<f32>, def_matrix: ColumnMatrix4<f32>,
} }
pub struct SharedGameState { pub struct GameContext {
pub flags: GameFlags,
pub key_state: KeyState,
pub key_trigger: KeyState,
pub texture_set: TextureSet, pub texture_set: TextureSet,
pub base_path: String, pub base_path: String,
pub stages: Vec<StageData>, pub stages: Vec<StageData>,
@ -80,16 +66,6 @@ pub struct SharedGameState {
pub canvas_size: (f32, f32), pub canvas_size: (f32, f32),
pub screen_size: (f32, f32), pub screen_size: (f32, f32),
pub next_scene: Option<Box<dyn Scene>>, pub next_scene: Option<Box<dyn Scene>>,
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 { impl Game {
@ -112,14 +88,8 @@ impl Game {
let s = Game { let s = Game {
scene: None, scene: None,
scaled_matrix: DrawParam::new() state: None,
.scale(Vector2::new(scale, scale)) ctx: GameContext {
.to_matrix(),
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), texture_set: TextureSet::new(base_path),
base_path: str!(base_path), base_path: str!(base_path),
stages: Vec::new(), stages: Vec::new(),
@ -129,16 +99,24 @@ impl Game {
screen_size, screen_size,
canvas_size, canvas_size,
next_scene: None, 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) Ok(s)
} }
fn update(&mut self, ctx: &mut Context) -> GameResult { fn update(&mut self, ctx: &mut Context) -> GameResult {
if self.scene.is_some() { if self.state.is_none() {
self.scene.as_mut().unwrap().tick(&mut self.state, ctx)?; 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)?;
} }
Ok(()) Ok(())
} }
@ -148,49 +126,52 @@ impl Game {
graphics::set_transform(ctx, self.scaled_matrix); graphics::set_transform(ctx, self.scaled_matrix);
graphics::apply_transformations(ctx)?; graphics::apply_transformations(ctx)?;
if self.scene.is_some() { if let (Some(scene), Some(state)) = (self.scene.as_mut(), self.state.as_mut()) {
self.scene.as_ref().unwrap().draw(&mut self.state, ctx)?; scene.draw(state, &mut self.ctx, ctx)?;
graphics::set_transform(ctx, self.def_matrix); graphics::set_transform(ctx, self.def_matrix);
graphics::apply_transformations(ctx)?; graphics::apply_transformations(ctx)?;
self.scene.as_ref().unwrap().overlay_draw(&mut self.state, ctx)?;
self.ui.draw(state, &mut self.ctx, ctx, scene)?;
} }
graphics::present(ctx)?; graphics::present(ctx)?;
Ok(()) Ok(())
} }
fn key_down_event(&mut self, _ctx: &mut Context, key_code: KeyCode, _key_mod: KeyMods, repeat: bool) { fn key_down_event(&mut self, _ctx: &mut Context, key_code: KeyCode, repeat: bool) {
if repeat { return; } if repeat { return; }
// todo: proper keymaps? // todo: proper keymaps?
let state = &mut self.state; if let Some(state) = self.state.as_mut() {
match key_code { match key_code {
KeyCode::Left => { state.key_state.set_left(true) } KeyCode::Left => { state.key_state.set_left(true) }
KeyCode::Right => { state.key_state.set_right(true) } KeyCode::Right => { state.key_state.set_right(true) }
KeyCode::Up => { state.key_state.set_up(true) } KeyCode::Up => { state.key_state.set_up(true) }
KeyCode::Down => { state.key_state.set_down(true) } KeyCode::Down => { state.key_state.set_down(true) }
KeyCode::Z => { state.key_state.set_jump(true) } KeyCode::Z => { state.key_state.set_jump(true) }
KeyCode::X => { state.key_state.set_fire(true) } KeyCode::X => { state.key_state.set_fire(true) }
KeyCode::A => { state.key_state.set_weapon_prev(true) } KeyCode::A => { state.key_state.set_weapon_prev(true) }
KeyCode::S => { state.key_state.set_weapon_next(true) } KeyCode::S => { state.key_state.set_weapon_next(true) }
_ => {} _ => {}
}
} }
} }
fn key_up_event(&mut self, _ctx: &mut Context, key_code: KeyCode, _key_mod: KeyMods) { fn key_up_event(&mut self, _ctx: &mut Context, key_code: KeyCode) {
let state = &mut self.state; if let Some(state) = self.state.as_mut() {
match key_code { match key_code {
KeyCode::Left => { state.key_state.set_left(false) } KeyCode::Left => { state.key_state.set_left(false) }
KeyCode::Right => { state.key_state.set_right(false) } KeyCode::Right => { state.key_state.set_right(false) }
KeyCode::Up => { state.key_state.set_up(false) } KeyCode::Up => { state.key_state.set_up(false) }
KeyCode::Down => { state.key_state.set_down(false) } KeyCode::Down => { state.key_state.set_down(false) }
KeyCode::Z => { state.key_state.set_jump(false) } KeyCode::Z => { state.key_state.set_jump(false) }
KeyCode::X => { state.key_state.set_fire(false) } KeyCode::X => { state.key_state.set_fire(false) }
KeyCode::A => { state.key_state.set_weapon_prev(false) } KeyCode::A => { state.key_state.set_weapon_prev(false) }
KeyCode::S => { state.key_state.set_weapon_next(false) } KeyCode::S => { state.key_state.set_weapon_next(false) }
_ => {} _ => {}
}
} }
} }
} }
@ -215,40 +196,35 @@ pub fn main() -> GameResult {
.add_resource_path(resource_dir); .add_resource_path(resource_dir);
let (ctx, event_loop) = &mut cb.build()?; let (ctx, event_loop) = &mut cb.build()?;
let state = &mut Game::new(ctx)?; let game = &mut Game::new(ctx)?;
state.state.next_scene = Some(Box::new(LoadingScene::new())); game.ctx.next_scene = Some(Box::new(LoadingScene::new()));
while ctx.continuing { while ctx.continuing {
ctx.timer_context.tick(); ctx.timer_context.tick();
event_loop.poll_events(|event| { event_loop.poll_events(|event| {
ctx.process_event(&event); ctx.process_event(&event);
game.ui.handle_events(ctx, &event);
match event { match event {
Event::WindowEvent { event, .. } => match event { Event::WindowEvent { event, .. } => match event {
WindowEvent::CloseRequested => event::quit(ctx), WindowEvent::CloseRequested => event::quit(ctx),
WindowEvent::KeyboardInput { WindowEvent::KeyboardInput {
input: input: KeyboardInput {
KeyboardInput {
state: ElementState::Pressed,
virtual_keycode: Some(keycode), virtual_keycode: Some(keycode),
modifiers, state: input_state,
.. ..
}, },
.. ..
} => { } => {
let repeat = keyboard::is_key_repeated(ctx); match input_state {
state.key_down_event(ctx, keycode, modifiers.into(), repeat); ElementState::Pressed => {
} let repeat = keyboard::is_key_repeated(ctx);
WindowEvent::KeyboardInput { game.key_down_event(ctx, keycode, repeat);
input: }
KeyboardInput { ElementState::Released => {
state: ElementState::Released, game.key_up_event(ctx, keycode);
virtual_keycode: Some(keycode), }
modifiers, }
..
},
..
} => {
state.key_up_event(ctx, keycode, modifiers.into());
} }
_ => {} _ => {}
}, },
@ -256,14 +232,13 @@ pub fn main() -> GameResult {
} }
}); });
state.update(ctx)?; game.update(ctx)?;
state.draw(ctx)?; game.draw(ctx)?;
if state.state.next_scene.is_some() { if game.ctx.next_scene.is_some() && game.state.is_some() {
mem::swap(&mut state.scene, &mut state.state.next_scene); mem::swap(&mut game.scene, &mut game.ctx.next_scene);
state.state.next_scene = None; game.ctx.next_scene = None;
game.scene.as_mut().unwrap().init(game.state.as_mut().unwrap(), &mut game.ctx, ctx)?;
state.scene.as_mut().unwrap().init(&mut state.state, ctx)?;
} }
} }
Ok(()) Ok(())

View file

@ -3,10 +3,10 @@ use num_traits::clamp;
use crate::bitfield; use crate::bitfield;
use crate::common::{Direction, Rect}; use crate::common::{Direction, Rect};
use crate::engine_constants::PhysicsConsts; use crate::engine_constants::{EngineConstants, PhysicsConsts};
use crate::entity::GameEntity; use crate::entity::GameEntity;
use crate::frame::Frame; use crate::game_state::GameState;
use crate::SharedGameState; use crate::GameContext;
use crate::str; use crate::str;
bitfield! { bitfield! {
@ -103,12 +103,8 @@ pub struct Player {
} }
impl Player { impl Player {
pub fn new(state: &mut SharedGameState, ctx: &mut Context) -> GameResult<Player> { pub fn new(constants: &EngineConstants, ctx: &mut Context) -> GameResult<Player> {
let constants = &state.constants;
let tex_player_name = str!("MyChar"); let tex_player_name = str!("MyChar");
state.texture_set.ensure_texture_loaded(ctx, constants, &tex_player_name)?;
Ok(Player { Ok(Player {
x: 0, x: 0,
y: 0, y: 0,
@ -146,7 +142,7 @@ impl Player {
}) })
} }
fn tick_normal(&mut self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult<()> { fn tick_normal(&mut self, state: &GameState, constants: &EngineConstants) -> GameResult<()> {
if self.cond.cond_x02() { if self.cond.cond_x02() {
return Ok(()); return Ok(());
} }
@ -224,23 +220,23 @@ impl Player {
if state.key_state.up() { if state.key_state.up() {
self.boost_sw = 2; self.boost_sw = 2;
self.xm = 0; self.xm = 0;
self.ym = state.constants.booster.b2_0_up; self.ym = constants.booster.b2_0_up;
} else if state.key_state.left() { } else if state.key_state.left() {
self.boost_sw = 2; self.boost_sw = 2;
self.xm = 0; self.xm = 0;
self.ym = state.constants.booster.b2_0_left; self.ym = constants.booster.b2_0_left;
} else if state.key_state.right() { } else if state.key_state.right() {
self.boost_sw = 2; self.boost_sw = 2;
self.xm = 0; self.xm = 0;
self.ym = state.constants.booster.b2_0_right; self.ym = constants.booster.b2_0_right;
} else if state.key_state.down() { } else if state.key_state.down() {
self.boost_sw = 2; self.boost_sw = 2;
self.xm = 0; self.xm = 0;
self.ym = state.constants.booster.b2_0_down; self.ym = constants.booster.b2_0_down;
} else { } else {
self.boost_sw = 2; self.boost_sw = 2;
self.xm = 0; self.xm = 0;
self.ym = state.constants.booster.b2_0_up_nokey; self.ym = constants.booster.b2_0_up_nokey;
} }
} }
} }
@ -455,11 +451,11 @@ impl Player {
Ok(()) Ok(())
} }
fn tick_stream(&mut self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult<()> { fn tick_stream(&mut self, state: &GameState, constants: &EngineConstants) -> GameResult<()> {
Ok(()) Ok(())
} }
fn tick_animation(&mut self, state: &SharedGameState) { fn tick_animation(&mut self, state: &GameState, constants: &EngineConstants) {
if self.cond.cond_x02() { if self.cond.cond_x02() {
return; return;
} }
@ -524,10 +520,10 @@ impl Player {
match self.direction { match self.direction {
Direction::Left => { Direction::Left => {
self.anim_rect = state.constants.my_char.animations_left[self.anim_num]; self.anim_rect = constants.my_char.animations_left[self.anim_num];
} }
Direction::Right => { Direction::Right => {
self.anim_rect = state.constants.my_char.animations_right[self.anim_num]; self.anim_rect = constants.my_char.animations_right[self.anim_num];
} }
_ => {} _ => {}
} }
@ -537,7 +533,12 @@ impl Player {
} }
impl GameEntity for Player { impl GameEntity for Player {
fn tick(&mut self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult<()> { 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 {
if !self.cond.visible() { if !self.cond.visible() {
return Ok(()); return Ok(());
} }
@ -559,31 +560,31 @@ impl GameEntity for Player {
// AirProcess(); // todo // AirProcess(); // todo
} }
self.tick_normal(state, ctx)?; self.tick_normal(state, constants)?;
} }
1 => { 1 => {
self.tick_stream(state, ctx)?; self.tick_stream(state, constants)?;
} }
_ => {} _ => {}
} }
self.cond.set_cond_x20(false); self.cond.set_cond_x20(false);
self.tick_animation(state); self.tick_animation(state, constants);
Ok(()) Ok(())
} }
fn draw(&self, state: &mut SharedGameState, ctx: &mut Context, frame: &Frame) -> GameResult<()> { fn draw(&self, state: &GameState, game_ctx: &mut GameContext, ctx: &mut Context) -> GameResult {
if !self.cond.visible() || self.cond.cond_x02() { if !self.cond.visible() || self.cond.cond_x02() {
return Ok(()); return Ok(());
} }
// todo draw weapon // todo draw weapon
if let Some(batch) = state.texture_set.tex_map.get_mut(&self.tex_player_name) { if let Some(batch) = game_ctx.texture_set.tex_map.get_mut(&self.tex_player_name) {
batch.add_rect( batch.add_rect(
(((self.x - self.view.left as isize) / 0x200) - (frame.x / 0x200)) as f32, (((self.x - self.view.left as isize) / 0x200) - (state.frame.x / 0x200)) as f32,
(((self.y - self.view.top as isize) / 0x200) - (frame.y / 0x200)) as f32, (((self.y - self.view.top as isize) / 0x200) - (state.frame.y / 0x200)) as f32,
&self.anim_rect, &self.anim_rect,
); );
batch.draw(ctx)?; batch.draw(ctx)?;

View file

@ -1,14 +1,13 @@
use num_traits::clamp; use num_traits::clamp;
use crate::game_state::GameState;
use crate::player::Player; use crate::player::Player;
use crate::stage::Stage;
use crate::SharedGameState;
const OFF_X: &[isize; 4] = &[0, 1, 0, 1]; const OFF_X: &[isize; 4] = &[0, 1, 0, 1];
const OFF_Y: &[isize; 4] = &[0, 0, 1, 1]; const OFF_Y: &[isize; 4] = &[0, 0, 1, 1];
impl Player { impl Player {
fn judge_hit_block(&mut self, state: &SharedGameState, x: isize, y: isize) { fn judge_hit_block(&mut self, x: isize, y: isize, state: &GameState) {
// left wall // left wall
if (self.y - self.hit.top as isize) < (y * 0x10 + 4) * 0x200 if (self.y - self.hit.top as isize) < (y * 0x10 + 4) * 0x200
&& self.y + self.hit.bottom as isize > (y * 0x10 - 4) * 0x200 && self.y + self.hit.bottom as isize > (y * 0x10 - 4) * 0x200
@ -82,7 +81,7 @@ impl Player {
} }
} }
fn judge_hit_triangle_a(&mut self, state: &SharedGameState, x: isize, y: isize) { fn judge_hit_triangle_a(&mut self, x: isize, y: isize) {
if self.x < (x * 0x10 + 8) * 0x200 if self.x < (x * 0x10 + 8) * 0x200
&& 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 && (self.y - self.hit.top as isize) < (y * 0x10 * 0x200) - (self.x - x * 0x10 * 0x200) / 2 + 0x800
@ -101,7 +100,7 @@ impl Player {
} }
} }
fn judge_hit_triangle_b(&mut self, state: &SharedGameState, x: isize, y: isize) { fn judge_hit_triangle_b(&mut self, x: isize, y: isize) {
if self.x < (x * 0x10 + 8) * 0x200 if self.x < (x * 0x10 + 8) * 0x200
&& 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 && (self.y - self.hit.top as isize) < (y * 0x10 * 0x200) - (self.x - x * 0x10 * 0x200) / 2 - 0x800
@ -120,7 +119,7 @@ impl Player {
} }
} }
fn judge_hit_triangle_c(&mut self, state: &SharedGameState, x: isize, y: isize) { fn judge_hit_triangle_c(&mut self, x: isize, y: isize) {
if self.x < (x * 0x10 + 8) * 0x200 if self.x < (x * 0x10 + 8) * 0x200
&& 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 && (self.y - self.hit.top as isize) < (y * 0x10 * 0x200) + (self.x - x * 0x10 * 0x200) / 2 - 0x800
@ -139,7 +138,7 @@ impl Player {
} }
} }
fn judge_hit_triangle_d(&mut self, state: &SharedGameState, x: isize, y: isize) { fn judge_hit_triangle_d(&mut self, x: isize, y: isize) {
if (self.x < (x * 0x10 + 8) * 0x200) if (self.x < (x * 0x10 + 8) * 0x200)
&& (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 && (self.y - self.hit.top as isize) < (y * 0x10 * 0x200) + (self.x - x * 0x10 * 0x200) / 2 + 0x800
@ -158,7 +157,7 @@ impl Player {
} }
} }
fn judge_hit_triangle_e(&mut self, state: &SharedGameState, x: isize, y: isize) { fn judge_hit_triangle_e(&mut self, x: isize, y: isize) {
self.flags.set_flag_x10000(true); self.flags.set_flag_x10000(true);
if (self.x < (x * 0x10 + 8) * 0x200) if (self.x < (x * 0x10 + 8) * 0x200)
@ -180,7 +179,7 @@ impl Player {
} }
} }
fn judge_hit_triangle_f(&mut self, state: &SharedGameState, x: isize, y: isize) { fn judge_hit_triangle_f(&mut self, x: isize, y: isize) {
self.flags.set_flag_x20000(true); self.flags.set_flag_x20000(true);
if (self.x < (x * 0x10 + 8) * 0x200) if (self.x < (x * 0x10 + 8) * 0x200)
@ -202,7 +201,7 @@ impl Player {
} }
} }
fn judge_hit_triangle_g(&mut self, state: &SharedGameState, x: isize, y: isize) { fn judge_hit_triangle_g(&mut self, x: isize, y: isize) {
self.flags.set_flag_x40000(true); self.flags.set_flag_x40000(true);
if (self.x < (x * 0x10 + 8) * 0x200) if (self.x < (x * 0x10 + 8) * 0x200)
@ -224,7 +223,7 @@ impl Player {
} }
} }
fn judge_hit_triangle_h(&mut self, state: &SharedGameState, x: isize, y: isize) { fn judge_hit_triangle_h(&mut self, x: isize, y: isize) {
self.flags.set_flag_x80000(true); self.flags.set_flag_x80000(true);
if (self.x < (x * 0x10 + 8) * 0x200) if (self.x < (x * 0x10 + 8) * 0x200)
@ -246,7 +245,7 @@ impl Player {
} }
} }
fn judge_hit_water(&mut self, state: &SharedGameState, x: isize, y: isize) { fn judge_hit_water(&mut self, x: isize, y: isize) {
if (self.x - self.hit.right as isize) < (x * 0x10 + 5) * 0x200 if (self.x - self.hit.right as isize) < (x * 0x10 + 5) * 0x200
&& (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 && (self.y - self.hit.top as isize) < (y * 0x10 + 5) * 0x200
@ -255,55 +254,55 @@ impl Player {
} }
} }
pub fn tick_map_collisions(&mut self, state: &SharedGameState, stage: &Stage) { pub fn tick_map_collisions(&mut self, state: &GameState) {
let x = clamp(self.x / 0x10 / 0x200, 0, stage.map.width as isize); let x = clamp(self.x / 0x10 / 0x200, 0, state.stage.map.width as isize);
let y = clamp(self.y / 0x10 / 0x200, 0, stage.map.height as isize); let y = clamp(self.y / 0x10 / 0x200, 0, state.stage.map.height as isize);
for (ox, oy) in OFF_X.iter().zip(OFF_Y) { for (ox, oy) in OFF_X.iter().zip(OFF_Y) {
let attrib = stage.map.get_attribute((x + *ox) as usize, (y + *oy) as usize); let attrib = state.stage.map.get_attribute((x + *ox) as usize, (y + *oy) as usize);
match attrib { match attrib {
// Block // Block
0x02 | 0x60 => { 0x02 | 0x60 => {
self.judge_hit_water(state, x + *ox, y + *oy); self.judge_hit_water(x + *ox, y + *oy);
} }
0x05 | 0x41 | 0x43 | 0x46 => { 0x05 | 0x41 | 0x43 | 0x46 => {
self.judge_hit_block(state, x + *ox, y + *oy); self.judge_hit_block(x + *ox, y + *oy, state);
} }
0x50 | 0x70 => { 0x50 | 0x70 => {
self.judge_hit_triangle_a(state, x + *ox, y + *oy); self.judge_hit_triangle_a(x + *ox, y + *oy);
if attrib & 0x20 != 0 { self.judge_hit_water(state, x + *ox, y + *oy); } if attrib & 0x20 != 0 { self.judge_hit_water(x + *ox, y + *oy); }
} }
0x51 | 0x71 => { 0x51 | 0x71 => {
self.judge_hit_triangle_b(state, x + *ox, y + *oy); self.judge_hit_triangle_b(x + *ox, y + *oy);
if attrib & 0x20 != 0 { self.judge_hit_water(state, x + *ox, y + *oy); } if attrib & 0x20 != 0 { self.judge_hit_water(x + *ox, y + *oy); }
} }
0x52 | 0x72 => { 0x52 | 0x72 => {
self.judge_hit_triangle_c(state, x + *ox, y + *oy); self.judge_hit_triangle_c(x + *ox, y + *oy);
if attrib & 0x20 != 0 { self.judge_hit_water(state, x + *ox, y + *oy); } if attrib & 0x20 != 0 { self.judge_hit_water(x + *ox, y + *oy); }
} }
0x53 | 0x73 => { 0x53 | 0x73 => {
self.judge_hit_triangle_d(state, x + *ox, y + *oy); self.judge_hit_triangle_d(x + *ox, y + *oy);
if attrib & 0x20 != 0 { self.judge_hit_water(state, x + *ox, y + *oy); } if attrib & 0x20 != 0 { self.judge_hit_water(x + *ox, y + *oy); }
} }
0x54 | 0x74 => { 0x54 | 0x74 => {
self.judge_hit_triangle_e(state, x + *ox, y + *oy); self.judge_hit_triangle_e(x + *ox, y + *oy);
if attrib & 0x20 != 0 { self.judge_hit_water(state, x + *ox, y + *oy); } if attrib & 0x20 != 0 { self.judge_hit_water(x + *ox, y + *oy); }
} }
0x55 | 0x75 => { 0x55 | 0x75 => {
self.judge_hit_triangle_f(state, x + *ox, y + *oy); self.judge_hit_triangle_f(x + *ox, y + *oy);
if attrib & 0x20 != 0 { self.judge_hit_water(state, x + *ox, y + *oy); } if attrib & 0x20 != 0 { self.judge_hit_water(x + *ox, y + *oy); }
} }
0x56 | 0x76 => { 0x56 | 0x76 => {
self.judge_hit_triangle_g(state, x + *ox, y + *oy); self.judge_hit_triangle_g(x + *ox, y + *oy);
if attrib & 0x20 != 0 { self.judge_hit_water(state, x + *ox, y + *oy); } if attrib & 0x20 != 0 { self.judge_hit_water(x + *ox, y + *oy); }
} }
0x57 | 0x77 => { 0x57 | 0x77 => {
self.judge_hit_triangle_h(state, x + *ox, y + *oy); self.judge_hit_triangle_h(x + *ox, y + *oy);
if attrib & 0x20 != 0 { self.judge_hit_water(state, x + *ox, y + *oy); } if attrib & 0x20 != 0 { self.judge_hit_water(x + *ox, y + *oy); }
} }
0x61 => { 0x61 => {
self.judge_hit_water(state, x + *ox, y + *oy); self.judge_hit_water(x + *ox, y + *oy);
self.judge_hit_block(state, x + *ox, y + *oy); self.judge_hit_block(x + *ox, y + *oy, state);
} }
_ => {} _ => {}
} }

View file

@ -1,22 +1,18 @@
use ggez::{Context, GameResult}; use ggez::{Context, GameResult};
use ggez::GameError::EventLoopError;
use ggez::nalgebra::clamp; use ggez::nalgebra::clamp;
use log::info;
use num_traits::abs;
use crate::common::Rect; use crate::common::Rect;
use crate::entity::GameEntity; use crate::entity::GameEntity;
use crate::frame::Frame; use crate::game_state::GameState;
use crate::player::Player; use crate::GameContext;
use crate::scene::Scene; use crate::scene::Scene;
use crate::SharedGameState; use crate::stage::BackgroundType;
use crate::stage::{BackgroundType, Stage};
use crate::str; use crate::str;
use crate::live_debugger::LiveDebugger;
pub struct GameScene { pub struct GameScene {
pub tick: usize, debugger: LiveDebugger,
pub stage: Stage,
pub frame: Frame,
pub player: Player,
tex_tileset_name: String, tex_tileset_name: String,
tex_background_name: String, tex_background_name: String,
tex_hud_name: String, tex_hud_name: String,
@ -38,28 +34,17 @@ pub enum Alignment {
} }
impl GameScene { impl GameScene {
pub fn new(state: &mut SharedGameState, ctx: &mut Context, id: usize) -> GameResult<Self> { pub fn new(state: &GameState, game_ctx: &mut GameContext, ctx: &mut Context) -> GameResult<Self> {
let stage = Stage::load(ctx, &state.base_path, &state.stages[id])?; let tex_tileset_name = str!(["Stage/", &state.stage.data.tileset.filename()].join(""));
info!("Loaded stage: {}", stage.data.name); let tex_background_name = state.stage.data.background.filename();
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"); let tex_hud_name = str!("TextBox");
state.texture_set.ensure_texture_loaded(ctx, &state.constants, &tex_tileset_name)?; game_ctx.texture_set.ensure_texture_loaded(ctx, &game_ctx.constants, &tex_tileset_name)?;
state.texture_set.ensure_texture_loaded(ctx, &state.constants, &tex_background_name)?; game_ctx.texture_set.ensure_texture_loaded(ctx, &game_ctx.constants, &tex_background_name)?;
state.texture_set.ensure_texture_loaded(ctx, &state.constants, &tex_hud_name)?; game_ctx.texture_set.ensure_texture_loaded(ctx, &game_ctx.constants, &tex_hud_name)?;
Ok(Self { Ok(Self {
tick: 0, debugger: LiveDebugger::new(),
stage,
player: Player::new(state, ctx)?,
frame: Frame {
x: 0,
y: 0,
wait: 16,
},
tex_tileset_name, tex_tileset_name,
tex_background_name, tex_background_name,
tex_hud_name, tex_hud_name,
@ -68,8 +53,8 @@ impl GameScene {
}) })
} }
fn draw_number(&self, x: f32, y: f32, val: usize, align: Alignment, state: &mut SharedGameState, ctx: &mut Context) -> GameResult { fn draw_number(&self, x: f32, y: f32, val: usize, align: Alignment, game_ctx: &mut GameContext, ctx: &mut Context) -> GameResult {
let set = state.texture_set.tex_map.get_mut(&self.tex_hud_name); let set = game_ctx.texture_set.tex_map.get_mut(&self.tex_hud_name);
if set.is_none() { if set.is_none() {
return Ok(()); return Ok(());
} }
@ -87,12 +72,11 @@ impl GameScene {
Ok(()) Ok(())
} }
fn draw_hud(&self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult { fn draw_hud(&self, state: &GameState, game_ctx: &mut GameContext, ctx: &mut Context) -> GameResult {
let set = state.texture_set.tex_map.get_mut(&self.tex_hud_name); let set = game_ctx.texture_set.tex_map.get_mut(&self.tex_hud_name);
if set.is_none() { if set.is_none() {
return Ok(()); return Ok(());
} }
let batch = set.unwrap(); let batch = set.unwrap();
// todo: max ammo display // todo: max ammo display
@ -114,30 +98,30 @@ impl GameScene {
&Rect::<usize>::new_size(0, 40, 64, 8)); &Rect::<usize>::new_size(0, 40, 64, 8));
// bar // bar
batch.add_rect(40.0, 40.0, batch.add_rect(40.0, 40.0,
&Rect::<usize>::new_size(0, 32, ((self.life_bar as usize * 40) / self.player.max_life as usize) - 1, 8)); &Rect::<usize>::new_size(0, 32, ((self.life_bar as usize * 40) / state.player().max_life as usize) - 1, 8));
// life // life
batch.add_rect(40.0, 40.0, batch.add_rect(40.0, 40.0,
&Rect::<usize>::new_size(0, 24, ((self.player.life as usize * 40) / self.player.max_life as usize) - 1, 8)); &Rect::<usize>::new_size(0, 24, ((state.player().life as usize * 40) / state.player().max_life as usize) - 1, 8));
batch.draw(ctx)?; batch.draw(ctx)?;
self.draw_number(40.0, 40.0, self.life_bar as usize, Alignment::Right, state, ctx)?; self.draw_number(40.0, 40.0, self.life_bar as usize, Alignment::Right, game_ctx, ctx)?;
Ok(()) Ok(())
} }
fn draw_background(&self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult { fn draw_background(&self, state: &GameState, game_ctx: &mut GameContext, ctx: &mut Context) -> GameResult {
let set = state.texture_set.tex_map.get_mut(&self.tex_background_name); let set = game_ctx.texture_set.tex_map.get_mut(&self.tex_background_name);
if set.is_none() { if set.is_none() {
return Ok(()); return Ok(());
} }
let batch = set.unwrap(); let batch = set.unwrap();
match self.stage.data.background_type { match state.stage.data.background_type {
BackgroundType::Stationary => { BackgroundType::Stationary => {
let count_x = state.canvas_size.0 as usize / batch.width() + 1; let count_x = game_ctx.canvas_size.0 as usize / batch.width() + 1;
let count_y = state.canvas_size.1 as usize / batch.height() + 1; let count_y = game_ctx.canvas_size.1 as usize / batch.height() + 1;
for y in 0..count_y { for y in 0..count_y {
for x in 0..count_x { for x in 0..count_x {
@ -146,11 +130,11 @@ impl GameScene {
} }
} }
BackgroundType::MoveDistant => { BackgroundType::MoveDistant => {
let off_x = self.frame.x as usize / 2 % (batch.width() * 0x200); let off_x = state.frame.x as usize / 2 % (batch.width() * 0x200);
let off_y = self.frame.y as usize / 2 % (batch.height() * 0x200); let off_y = state.frame.y as usize / 2 % (batch.height() * 0x200);
let count_x = state.canvas_size.0 as usize / batch.width() + 2; let count_x = game_ctx.canvas_size.0 as usize / batch.width() + 2;
let count_y = state.canvas_size.1 as usize / batch.height() + 2; let count_y = game_ctx.canvas_size.1 as usize / batch.height() + 2;
for y in 0..count_y { for y in 0..count_y {
for x in 0..count_x { for x in 0..count_x {
@ -164,27 +148,27 @@ impl GameScene {
BackgroundType::Black => {} BackgroundType::Black => {}
BackgroundType::Autoscroll => {} BackgroundType::Autoscroll => {}
BackgroundType::OutsideWind | BackgroundType::Outside => { BackgroundType::OutsideWind | BackgroundType::Outside => {
let offset = (self.tick % 640) as isize; let offset = (state.tick % 640) as isize;
batch.add_rect(((state.canvas_size.0 - 320.0) / 2.0).floor(), 0.0, batch.add_rect(((game_ctx.canvas_size.0 - 320.0) / 2.0).floor(), 0.0,
&Rect::<usize>::new_size(0, 0, 320, 88)); &Rect::<usize>::new_size(0, 0, 320, 88));
for x in ((-offset / 2)..(state.canvas_size.0 as isize)).step_by(320) { for x in ((-offset / 2)..(game_ctx.canvas_size.0 as isize)).step_by(320) {
batch.add_rect(x as f32, 88.0, batch.add_rect(x as f32, 88.0,
&Rect::<usize>::new_size(0, 88, 320, 35)); &Rect::<usize>::new_size(0, 88, 320, 35));
} }
for x in ((-offset % 320)..(state.canvas_size.0 as isize)).step_by(320) { for x in ((-offset % 320)..(game_ctx.canvas_size.0 as isize)).step_by(320) {
batch.add_rect(x as f32, 123.0, batch.add_rect(x as f32, 123.0,
&Rect::<usize>::new_size(0, 123, 320, 23)); &Rect::<usize>::new_size(0, 123, 320, 23));
} }
for x in ((-offset * 2)..(state.canvas_size.0 as isize)).step_by(320) { for x in ((-offset * 2)..(game_ctx.canvas_size.0 as isize)).step_by(320) {
batch.add_rect(x as f32, 146.0, batch.add_rect(x as f32, 146.0,
&Rect::<usize>::new_size(0, 146, 320, 30)); &Rect::<usize>::new_size(0, 146, 320, 30));
} }
for x in ((-offset * 4)..(state.canvas_size.0 as isize)).step_by(320) { for x in ((-offset * 4)..(game_ctx.canvas_size.0 as isize)).step_by(320) {
batch.add_rect(x as f32, 176.0, batch.add_rect(x as f32, 176.0,
&Rect::<usize>::new_size(0, 176, 320, 64)); &Rect::<usize>::new_size(0, 176, 320, 64));
} }
@ -196,34 +180,34 @@ impl GameScene {
Ok(()) Ok(())
} }
fn draw_tiles(&self, state: &mut SharedGameState, ctx: &mut Context, layer: TileLayer) -> GameResult { fn draw_tiles(&self, layer: TileLayer, state: &GameState, game_ctx: &mut GameContext, ctx: &mut Context) -> GameResult {
if let Some(batch) = state.texture_set.tex_map.get_mut(&self.tex_tileset_name) { if let Some(batch) = game_ctx.texture_set.tex_map.get_mut(&self.tex_tileset_name) {
let mut rect = Rect::<usize>::new(0, 0, 16, 16); let mut rect = Rect::<usize>::new(0, 0, 16, 16);
let tile_start_x = clamp(self.frame.x / 0x200 / 16, 0, self.stage.map.width as isize) as usize; let tile_start_x = clamp(state.frame.x / 0x200 / 16, 0, state.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_start_y = clamp(state.frame.y / 0x200 / 16, 0, state.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_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((self.frame.y / 0x200 + 8 + state.canvas_size.1 as isize) / 16 + 1, 0, self.stage.map.height 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;
for y in tile_start_y..tile_end_y { for y in tile_start_y..tile_end_y {
for x in tile_start_x..tile_end_x { for x in tile_start_x..tile_end_x {
let tile = *self.stage.map.tiles let tile = *state.stage.map.tiles
.get((y * self.stage.map.width) + x) .get((y * state.stage.map.width) + x)
.unwrap(); .unwrap();
match layer { match layer {
TileLayer::Background => { TileLayer::Background => {
if self.stage.map.attrib[tile as usize] >= 0x20 { if state.stage.map.attrib[tile as usize] >= 0x20 {
continue; continue;
} }
} }
TileLayer::Foreground => { TileLayer::Foreground => {
let attr = self.stage.map.attrib[tile as usize]; let attr = state.stage.map.attrib[tile as usize];
if attr < 0x40 || attr >= 0x80 { if attr < 0x40 || attr >= 0x80 {
continue; continue;
} }
} }
_ => {} TileLayer::All => {}
} }
rect.left = (tile as usize % 16) * 16; rect.left = (tile as usize % 16) * 16;
@ -231,7 +215,7 @@ impl GameScene {
rect.right = rect.left + 16; rect.right = rect.left + 16;
rect.bottom = rect.top + 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.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);
} }
} }
@ -242,35 +226,30 @@ impl GameScene {
} }
impl Scene for GameScene { impl Scene for GameScene {
fn init(&mut self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult { fn init(&mut self, state: &mut GameState, game_ctx: &mut GameContext, 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(()) Ok(())
} }
fn tick(&mut self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult { fn tick(&mut self, state: &mut GameState, game_ctx: &mut GameContext, ctx: &mut Context) -> GameResult {
state.update_key_trigger(); state.update_key_trigger();
if state.flags.flag_x01() { /*if state.flags.flag_x01() {
self.player.tick(state, ctx)?; 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);
}*/
self.player.flags.0 = 0; state.tick = state.tick.wrapping_add(1);
self.player.tick_map_collisions(state, &self.stage); //state.tick(game_ctx, ctx)?;
self.frame.update(state, &self.player, &self.stage);
}
if state.flags.control_enabled() { if state.flags.control_enabled() {
// update health bar // update health bar
if self.life_bar < self.player.life as usize { if self.life_bar < state.player().life as usize {
self.life_bar = self.player.life as usize; self.life_bar = state.player().life as usize;
} }
if self.life_bar > self.player.life as usize { if self.life_bar > state.player().life as usize {
self.life_bar_count += 1; self.life_bar_count += 1;
if self.life_bar_count > 30 { if self.life_bar_count > 30 {
self.life_bar -= 1; self.life_bar -= 1;
@ -280,20 +259,21 @@ impl Scene for GameScene {
} }
} }
self.tick = self.tick.wrapping_add(1);
Ok(()) Ok(())
} }
fn draw(&self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult { fn draw(&self, state: &GameState, game_ctx: &mut GameContext, ctx: &mut Context) -> GameResult {
self.draw_background(state, ctx)?; self.draw_background(state, game_ctx, ctx)?;
self.draw_tiles(state, ctx, TileLayer::Background)?; self.draw_tiles(TileLayer::Background, state, game_ctx, ctx)?;
self.player.draw(state, ctx, &self.frame)?; state.player().draw(state, game_ctx, ctx)?;
self.draw_tiles(state, ctx, TileLayer::Foreground)?; self.draw_tiles(TileLayer::Foreground, state, game_ctx, ctx)?;
self.draw_hud(state, game_ctx, ctx)?;
self.draw_hud(state, ctx)?; Ok(())
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)?;
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)?;
Ok(()) Ok(())
} }
} }

View file

@ -1,8 +1,8 @@
use ggez::{Context, GameResult}; use ggez::{Context, GameResult};
use crate::scene::game_scene::GameScene; use crate::game_state::GameState;
use crate::GameContext;
use crate::scene::Scene; use crate::scene::Scene;
use crate::SharedGameState;
use crate::stage::StageData; use crate::stage::StageData;
pub struct LoadingScene { pub struct LoadingScene {
@ -18,30 +18,32 @@ impl LoadingScene {
} }
impl Scene for LoadingScene { impl Scene for LoadingScene {
fn init(&mut self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult { fn init(&mut self, state: &mut GameState, game_ctx: &mut GameContext, ctx: &mut Context) -> GameResult {
state.texture_set.ensure_texture_loaded(ctx, &state.constants, "Loading")?; game_ctx.texture_set.ensure_texture_loaded(ctx, &game_ctx.constants, "Loading")?;
Ok(()) Ok(())
} }
fn tick(&mut self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult { fn tick(&mut self, state: &mut GameState, game_ctx: &mut GameContext, ctx: &mut Context) -> GameResult {
// deferred to let the loading image draw // deferred to let the loading image draw
if self.tick == 1 { if self.tick == 1 {
let stages = StageData::load_stage_table(ctx, &state.base_path)?; let stages = StageData::load_stage_table(ctx, &game_ctx.base_path)?;
state.stages = stages; game_ctx.stages = stages;
state.next_scene = Some(Box::new(GameScene::new(state, ctx, 53)?)); } else if self.tick == 2 {
state.init(game_ctx, ctx)?;
state.switch_to_stage(53, game_ctx, ctx)?;
} }
self.tick += 1; self.tick += 1;
Ok(()) Ok(())
} }
fn draw(&self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult { fn draw(&self, state: &GameState, game_ctx: &mut GameContext, ctx: &mut Context) -> GameResult {
let loading = state.texture_set.tex_map.get_mut("Loading"); let loading = game_ctx.texture_set.tex_map.get_mut("Loading");
if loading.is_some() { if loading.is_some() {
let img = loading.unwrap(); let img = loading.unwrap();
img.add(((state.canvas_size.0 - img.width() as f32) / 2.0).floor(), img.add(((game_ctx.canvas_size.0 - img.width() as f32) / 2.0).floor(),
((state.canvas_size.1 - img.height() as f32) / 2.0).floor()); ((game_ctx.canvas_size.1 - img.height() as f32) / 2.0).floor());
img.draw(ctx)?; img.draw(ctx)?;
} }

View file

@ -1,16 +1,17 @@
use ggez::{Context, GameResult}; use ggez::{Context, GameResult};
use crate::SharedGameState; use crate::GameContext;
use crate::game_state::GameState;
pub mod game_scene; pub mod game_scene;
pub mod loading_scene; pub mod loading_scene;
pub trait Scene { pub trait Scene {
fn init(&mut self, _state: &mut SharedGameState, _ctx: &mut Context) -> GameResult { Ok(()) } fn init(&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 tick(&mut self, _state: &mut GameState, _game_ctx: &mut GameContext, _ctx: &mut Context) -> GameResult { Ok(()) }
fn draw(&self, _state: &mut SharedGameState, _ctx: &mut Context) -> GameResult { Ok(()) } fn draw(&self, _state: &GameState, _game_ctx: &mut GameContext, _ctx: &mut Context) -> GameResult { Ok(()) }
fn overlay_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(()) }
} }

View file

@ -1,4 +1,4 @@
use std::io::{Cursor, Read}; use std::io::Cursor;
use ggez::{Context, GameResult}; use ggez::{Context, GameResult};

View file

@ -8,6 +8,7 @@ use ggez::GameError::ResourceLoadError;
use log::info; use log::info;
use crate::map::Map; use crate::map::Map;
use crate::str;
#[derive(Debug, PartialEq, Eq, Hash)] #[derive(Debug, PartialEq, Eq, Hash)]
pub struct NpcType { pub struct NpcType {
@ -374,6 +375,27 @@ pub struct Stage {
} }
impl 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<Self> { pub fn load(ctx: &mut Context, root: &str, data: &StageData) -> GameResult<Self> {
let map_file = filesystem::open(ctx, [root, "Stage/", &data.map, ".pxm"].join(""))?; 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(""))?; let attrib_file = filesystem::open(ctx, [root, "Stage/", &data.tileset.name, ".pxa"].join(""))?;

View file

@ -7,7 +7,7 @@ use ggez::graphics::{Drawable, DrawParam, FilterMode, Image, Rect};
use ggez::graphics::spritebatch::SpriteBatch; use ggez::graphics::spritebatch::SpriteBatch;
use ggez::nalgebra::{Point2, Vector2}; use ggez::nalgebra::{Point2, Vector2};
use itertools::Itertools; use itertools::Itertools;
use log::{debug, info}; use log::info;
use crate::common; use crate::common;
use crate::engine_constants::EngineConstants; use crate::engine_constants::EngineConstants;

104
src/ui.rs Normal file
View file

@ -0,0 +1,104 @@
use std::time::Instant;
use ggez::{Context, GameResult, graphics};
use ggez::GameError::RenderError;
use imgui::{FontConfig, FontSource};
use imgui_gfx_renderer::{Renderer, Shaders};
use imgui_gfx_renderer::gfx::format::Rgba8;
use imgui_gfx_renderer::gfx::handle::RenderTargetView;
use imgui_gfx_renderer::gfx::memory::Typed;
use imgui_winit_support::{HiDpiMode, WinitPlatform};
use crate::scene::Scene;
use crate::GameContext;
use crate::game_state::GameState;
mod types {
pub type Device = gfx_device_gl::Device;
pub type Factory = gfx_device_gl::Factory;
pub type Resources = gfx_device_gl::Resources;
}
pub struct UI {
pub imgui: imgui::Context,
pub platform: WinitPlatform,
pub renderer: Renderer<Rgba8, types::Resources>,
main_color: RenderTargetView<types::Resources, Rgba8>,
last_frame: Instant,
}
impl UI {
pub fn new(ctx: &mut Context) -> GameResult<Self> {
let mut imgui = imgui::Context::create();
imgui.set_ini_filename(None);
imgui.fonts().add_font(&[
FontSource::DefaultFontData {
config: Some(FontConfig::default()),
},
]);
imgui.style_mut().use_dark_colors();
let mut platform = WinitPlatform::init(&mut imgui);
platform.attach_window(imgui.io_mut(), graphics::window(ctx), HiDpiMode::Rounded);
let (factory, dev, _, _, color) = graphics::gfx_objects(ctx);
let shaders = {
let version = dev.get_info().shading_language;
if version.is_embedded {
if version.major >= 3 {
Shaders::GlSlEs300
} else {
Shaders::GlSlEs100
}
} else if version.major >= 4 {
Shaders::GlSl400
} else if version.major >= 3 {
if version.minor >= 2 {
Shaders::GlSl150
} else {
Shaders::GlSl130
}
} else {
Shaders::GlSl110
}
};
let renderer = Renderer::init(&mut imgui, factory, shaders)
.map_err(|e| RenderError(e.to_string()))?;
Ok(Self {
imgui,
platform,
renderer,
main_color: RenderTargetView::new(color),
last_frame: Instant::now(),
})
}
pub fn handle_events(&mut self, ctx: &mut Context, event: &winit::Event) {
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<dyn Scene>) -> GameResult {
{
let io = self.imgui.io_mut();
self.platform.prepare_frame(io, graphics::window(ctx)).map_err(|e| RenderError(e))?;
io.update_delta_time(self.last_frame);
self.last_frame = Instant::now();
}
let mut ui = self.imgui.frame();
scene.overlay_draw(state, game_ctx, ctx, &mut ui)?;
self.platform.prepare_render(&ui, graphics::window(ctx));
let draw_data = ui.render();
let (factory, dev, encoder, _, _) = graphics::gfx_objects(ctx);
self.renderer
.render(factory, encoder, &mut self.main_color, draw_data)
.map_err(|e| RenderError(e.to_string()))?;
encoder.flush(dev);
Ok(())
}
}