1
0
Fork 0
mirror of https://github.com/doukutsu-rs/doukutsu-rs synced 2025-12-02 01:18:37 +00:00

Better Save Menu UX (fixes #111)

This commit is contained in:
dawnDus 2022-04-10 15:57:19 -04:00
parent 68318e3a69
commit 339f822a80
No known key found for this signature in database
GPG key ID: 972AABDE81848F21
3 changed files with 113 additions and 62 deletions

View file

@ -13,6 +13,7 @@ pub mod pause_menu;
pub mod save_select_menu; pub mod save_select_menu;
pub mod settings_menu; pub mod settings_menu;
#[derive(Clone)]
pub enum MenuEntry { pub enum MenuEntry {
Hidden, Hidden,
Active(String), Active(String),
@ -23,6 +24,7 @@ pub enum MenuEntry {
DescriptiveOptions(String, usize, Vec<String>, Vec<String>), DescriptiveOptions(String, usize, Vec<String>, Vec<String>),
OptionsBar(String, f32), OptionsBar(String, f32),
SaveData(MenuSaveInfo), SaveData(MenuSaveInfo),
SaveDataSingle(MenuSaveInfo),
NewSave, NewSave,
} }
@ -38,6 +40,7 @@ impl MenuEntry {
MenuEntry::DescriptiveOptions(_, _, _, _) => 16.0, MenuEntry::DescriptiveOptions(_, _, _, _) => 16.0,
MenuEntry::OptionsBar(_, _) => 16.0, MenuEntry::OptionsBar(_, _) => 16.0,
MenuEntry::SaveData(_) => 32.0, MenuEntry::SaveData(_) => 32.0,
MenuEntry::SaveDataSingle(_) => 32.0,
MenuEntry::NewSave => 32.0, MenuEntry::NewSave => 32.0,
} }
} }
@ -53,6 +56,7 @@ impl MenuEntry {
MenuEntry::DescriptiveOptions(_, _, _, _) => true, MenuEntry::DescriptiveOptions(_, _, _, _) => true,
MenuEntry::OptionsBar(_, _) => true, MenuEntry::OptionsBar(_, _) => true,
MenuEntry::SaveData(_) => true, MenuEntry::SaveData(_) => true,
MenuEntry::SaveDataSingle(_) => true,
MenuEntry::NewSave => true, MenuEntry::NewSave => true,
} }
} }
@ -76,6 +80,7 @@ pub struct Menu {
anim_num: u16, anim_num: u16,
anim_wait: u16, anim_wait: u16,
custom_cursor: Cell<bool>, custom_cursor: Cell<bool>,
pub draw_cursor: bool,
} }
impl Menu { impl Menu {
@ -90,6 +95,7 @@ impl Menu {
anim_wait: 0, anim_wait: 0,
entries: Vec::new(), entries: Vec::new(),
custom_cursor: Cell::new(true), custom_cursor: Cell::new(true),
draw_cursor: true,
} }
} }
@ -152,6 +158,7 @@ impl Menu {
width = width.max(entry_width); width = width.max(entry_width);
} }
MenuEntry::SaveData(_) => {} MenuEntry::SaveData(_) => {}
MenuEntry::SaveDataSingle(_) => {}
MenuEntry::NewSave => {} MenuEntry::NewSave => {}
} }
} }
@ -271,6 +278,7 @@ impl Menu {
entry_y = self.entries[0..(self.selected)].iter().map(|e| e.height()).sum::<f64>().max(0.0) as u16; entry_y = self.entries[0..(self.selected)].iter().map(|e| e.height()).sum::<f64>().max(0.0) as u16;
} }
if self.draw_cursor {
if self.custom_cursor.get() { if self.custom_cursor.get() {
if let Ok(batch) = state.texture_set.get_or_load_batch(ctx, &state.constants, "MenuCursor") { if let Ok(batch) = state.texture_set.get_or_load_batch(ctx, &state.constants, "MenuCursor") {
rect.left = self.anim_num * 16; rect.left = self.anim_num * 16;
@ -323,6 +331,7 @@ impl Menu {
batch.draw(ctx)?; batch.draw(ctx)?;
} }
}
y = self.y as f32 + 8.0; y = self.y as f32 + 8.0;
for entry in &self.entries { for entry in &self.entries {
@ -481,7 +490,7 @@ impl Menu {
ctx, ctx,
)?; )?;
} }
MenuEntry::SaveData(save) => { MenuEntry::SaveData(save) | MenuEntry::SaveDataSingle(save) => {
let name = &state.stages[save.current_map as usize].name; let name = &state.stages[save.current_map as usize].name;
let bar_width = (save.life as f32 / save.max_life as f32 * 39.0) as u16; let bar_width = (save.life as f32 / save.max_life as f32 * 39.0) as u16;
let right_edge = self.x as f32 + self.width as f32 - 4.0; let right_edge = self.x as f32 + self.width as f32 - 4.0;

View file

@ -26,13 +26,16 @@ pub enum CurrentMenu {
SaveMenu, SaveMenu,
DifficultyMenu, DifficultyMenu,
DeleteConfirm, DeleteConfirm,
LoadConfirm,
} }
pub struct SaveSelectMenu { pub struct SaveSelectMenu {
pub saves: [MenuSaveInfo; 3], pub saves: [MenuSaveInfo; 3],
current_menu: CurrentMenu, current_menu: CurrentMenu,
save_menu: Menu, save_menu: Menu,
save_detailed: Menu,
difficulty_menu: Menu, difficulty_menu: Menu,
delete_confirm: Menu, delete_confirm: Menu,
load_confirm: Menu,
skip_difficulty_menu: bool, skip_difficulty_menu: bool,
} }
@ -42,16 +45,20 @@ impl SaveSelectMenu {
saves: [MenuSaveInfo::default(); 3], saves: [MenuSaveInfo::default(); 3],
current_menu: CurrentMenu::SaveMenu, current_menu: CurrentMenu::SaveMenu,
save_menu: Menu::new(0, 0, 230, 0), save_menu: Menu::new(0, 0, 230, 0),
save_detailed: Menu::new(0, 0, 230, 0),
difficulty_menu: Menu::new(0, 0, 130, 0), difficulty_menu: Menu::new(0, 0, 130, 0),
delete_confirm: Menu::new(0, 0, 75, 0), delete_confirm: Menu::new(0, 0, 75, 0),
load_confirm: Menu::new(0, 0, 75, 0),
skip_difficulty_menu: false, skip_difficulty_menu: false,
} }
} }
pub fn init(&mut self, state: &mut SharedGameState, ctx: &Context) -> GameResult { pub fn init(&mut self, state: &mut SharedGameState, ctx: &Context) -> GameResult {
self.save_menu = Menu::new(0, 0, 230, 0); self.save_menu = Menu::new(0, 0, 230, 0);
self.save_detailed = Menu::new(0, 0, 230, 0);
self.difficulty_menu = Menu::new(0, 0, 130, 0); self.difficulty_menu = Menu::new(0, 0, 130, 0);
self.delete_confirm = Menu::new(0, 0, 75, 0); self.delete_confirm = Menu::new(0, 0, 75, 0);
self.load_confirm = Menu::new(0, 0, 75, 0);
self.skip_difficulty_menu = false; self.skip_difficulty_menu = false;
for (iter, save) in self.saves.iter_mut().enumerate() { for (iter, save) in self.saves.iter_mut().enumerate() {
@ -72,7 +79,6 @@ impl SaveSelectMenu {
} }
self.save_menu.push_entry(MenuEntry::Active(state.t("common.back"))); self.save_menu.push_entry(MenuEntry::Active(state.t("common.back")));
self.save_menu.push_entry(MenuEntry::Disabled(state.t("menus.save_menu.delete_info")));
self.difficulty_menu.push_entry(MenuEntry::Disabled(state.t("menus.difficulty_menu.title"))); self.difficulty_menu.push_entry(MenuEntry::Disabled(state.t("menus.difficulty_menu.title")));
self.difficulty_menu.push_entry(MenuEntry::Active(state.t("menus.difficulty_menu.easy"))); self.difficulty_menu.push_entry(MenuEntry::Active(state.t("menus.difficulty_menu.easy")));
@ -88,6 +94,15 @@ impl SaveSelectMenu {
self.delete_confirm.selected = 2; self.delete_confirm.selected = 2;
self.load_confirm.push_entry(MenuEntry::Active(state.t("menus.main_menu.start")));
self.load_confirm.push_entry(MenuEntry::Active(state.t("menus.save_menu.delete_confirm")));
self.load_confirm.push_entry(MenuEntry::Active(state.t("common.back")));
self.save_detailed.draw_cursor = false;
if let MenuEntry::SaveData(save) = self.save_menu.entries[0] {
self.save_detailed.push_entry(MenuEntry::SaveDataSingle(save));
}
self.update_sizes(state); self.update_sizes(state);
Ok(()) Ok(())
@ -101,7 +116,7 @@ impl SaveSelectMenu {
self.save_menu.update_width(state); self.save_menu.update_width(state);
self.save_menu.update_height(); self.save_menu.update_height();
self.save_menu.x = ((state.canvas_size.0 - self.save_menu.width as f32) / 2.0).floor() as isize; self.save_menu.x = ((state.canvas_size.0 - self.save_menu.width as f32) / 2.0).floor() as isize;
self.save_menu.y = 30 + ((state.canvas_size.1 - self.save_menu.height as f32) / 2.0).floor() as isize; self.save_menu.y = ((state.canvas_size.1 - self.save_menu.height as f32) / 2.0).floor() as isize;
self.difficulty_menu.update_width(state); self.difficulty_menu.update_width(state);
self.difficulty_menu.update_height(); self.difficulty_menu.update_height();
@ -112,7 +127,17 @@ impl SaveSelectMenu {
self.delete_confirm.update_width(state); self.delete_confirm.update_width(state);
self.delete_confirm.update_height(); self.delete_confirm.update_height();
self.delete_confirm.x = ((state.canvas_size.0 - self.delete_confirm.width as f32) / 2.0).floor() as isize; self.delete_confirm.x = ((state.canvas_size.0 - self.delete_confirm.width as f32) / 2.0).floor() as isize;
self.delete_confirm.y = 30 + ((state.canvas_size.1 - self.delete_confirm.height as f32) / 2.0).floor() as isize self.delete_confirm.y = 30 + ((state.canvas_size.1 - self.delete_confirm.height as f32) / 2.0).floor() as isize;
self.load_confirm.update_width(state);
self.load_confirm.update_height();
self.load_confirm.x = ((state.canvas_size.0 - self.load_confirm.width as f32) / 2.0).floor() as isize;
self.load_confirm.y = 30 + ((state.canvas_size.1 - self.load_confirm.height as f32) / 2.0).floor() as isize;
self.save_detailed.update_width(state);
self.save_detailed.update_height();
self.save_detailed.x = ((state.canvas_size.0 - self.save_detailed.width as f32) / 2.0).floor() as isize;
self.save_detailed.y = -40 + ((state.canvas_size.1 - self.save_detailed.height as f32) / 2.0).floor() as isize;
} }
pub fn tick( pub fn tick(
@ -129,12 +154,15 @@ impl SaveSelectMenu {
MenuSelectionResult::Selected(slot, _) => { MenuSelectionResult::Selected(slot, _) => {
state.save_slot = slot + 1; state.save_slot = slot + 1;
if self.skip_difficulty_menu { if let Ok(_) =
state.reload_resources(ctx)?;
state.load_or_start_game(ctx)?;
} else if let Ok(_) =
filesystem::user_open(ctx, state.get_save_filename(state.save_slot).unwrap_or("".to_string())) filesystem::user_open(ctx, state.get_save_filename(state.save_slot).unwrap_or("".to_string()))
{ {
if let MenuEntry::SaveData(save) = self.save_menu.entries[slot] {
self.save_detailed.entries[0] = MenuEntry::SaveDataSingle(save);
}
self.current_menu = CurrentMenu::LoadConfirm;
self.load_confirm.selected = 0;
} else if self.skip_difficulty_menu {
state.reload_resources(ctx)?; state.reload_resources(ctx)?;
state.load_or_start_game(ctx)?; state.load_or_start_game(ctx)?;
} else { } else {
@ -142,12 +170,6 @@ impl SaveSelectMenu {
self.current_menu = CurrentMenu::DifficultyMenu; self.current_menu = CurrentMenu::DifficultyMenu;
} }
} }
MenuSelectionResult::Right(slot, _, _) => {
if slot <= 2 {
self.current_menu = CurrentMenu::DeleteConfirm;
self.delete_confirm.selected = 2;
}
}
_ => (), _ => (),
}, },
CurrentMenu::DifficultyMenu => match self.difficulty_menu.tick(controller, state) { CurrentMenu::DifficultyMenu => match self.difficulty_menu.tick(controller, state) {
@ -181,6 +203,21 @@ impl SaveSelectMenu {
self.save_menu.entries[self.save_menu.selected] = MenuEntry::NewSave; self.save_menu.entries[self.save_menu.selected] = MenuEntry::NewSave;
self.current_menu = CurrentMenu::SaveMenu; self.current_menu = CurrentMenu::SaveMenu;
} }
MenuSelectionResult::Selected(2, _) | MenuSelectionResult::Canceled => {
self.current_menu = CurrentMenu::LoadConfirm;
self.load_confirm.selected = 0;
}
_ => (),
},
CurrentMenu::LoadConfirm => match self.load_confirm.tick(controller, state) {
MenuSelectionResult::Selected(0, _) => {
state.reload_resources(ctx)?;
state.load_or_start_game(ctx)?;
}
MenuSelectionResult::Selected(1, _) => {
self.current_menu = CurrentMenu::DeleteConfirm;
self.delete_confirm.selected = 2;
}
MenuSelectionResult::Selected(2, _) | MenuSelectionResult::Canceled => { MenuSelectionResult::Selected(2, _) | MenuSelectionResult::Canceled => {
self.current_menu = CurrentMenu::SaveMenu; self.current_menu = CurrentMenu::SaveMenu;
} }
@ -200,8 +237,13 @@ impl SaveSelectMenu {
self.difficulty_menu.draw(state, ctx)?; self.difficulty_menu.draw(state, ctx)?;
} }
CurrentMenu::DeleteConfirm => { CurrentMenu::DeleteConfirm => {
self.save_detailed.draw(state, ctx)?;
self.delete_confirm.draw(state, ctx)?; self.delete_confirm.draw(state, ctx)?;
} }
CurrentMenu::LoadConfirm => {
self.save_detailed.draw(state, ctx)?;
self.load_confirm.draw(state, ctx)?;
}
} }
Ok(()) Ok(())
} }

View file

@ -352,7 +352,7 @@ impl Scene for TitleScene {
fn draw(&self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult { fn draw(&self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult {
self.background.draw(state, ctx, &self.frame, &self.textures, &self.stage)?; self.background.draw(state, ctx, &self.frame, &self.textures, &self.stage)?;
{ if self.current_menu != CurrentMenu::SaveSelectMenu {
let batch = state.texture_set.get_or_load_batch(ctx, &state.constants, "Title")?; let batch = state.texture_set.get_or_load_batch(ctx, &state.constants, "Title")?;
batch.add_rect( batch.add_rect(
((state.canvas_size.0 - state.constants.title.logo_rect.width() as f32) / 2.0).floor(), ((state.canvas_size.0 - state.constants.title.logo_rect.width() as f32) / 2.0).floor(),