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

make pausing on focus loss toggleable

This commit is contained in:
Sallai József 2022-07-25 11:41:20 +03:00
parent 2a792db797
commit fee63f2600
6 changed files with 145 additions and 36 deletions

View file

@ -116,10 +116,14 @@
"language": "Language...", "language": "Language...",
"game_timing": { "behavior": "Behavior...",
"entry": "Game timing:", "behavior_menu": {
"50tps": "50tps (freeware)", "game_timing": {
"60tps": "60tps (CS+)" "entry": "Game timing:",
"50tps": "50tps (freeware)",
"60tps": "60tps (CS+)"
},
"pause_on_focus_loss": "Pause on focus loss:"
} }
} }
}, },

View file

@ -105,11 +105,17 @@
}, },
"soundtrack": "サウンドトラック: {soundtrack}" "soundtrack": "サウンドトラック: {soundtrack}"
}, },
"language": "言語", "language": "言語",
"game_timing": {
"entry": "ゲームのタイミング:", "behavior": "動作",
"50tps": "50tps (freeware)", "behavior_menu": {
"60tps": "60tps (CS+)" "game_timing": {
"entry": "ゲームのタイミング:",
"50tps": "50tps (freeware)",
"60tps": "60tps (CS+)"
},
"pause_on_focus_loss": "フォーカスが外れた時のポーズ:"
} }
} }
}, },

View file

@ -237,8 +237,25 @@ impl BackendEventLoop for SDL2EventLoop {
state.shutdown(); state.shutdown();
} }
Event::Window { win_event, .. } => match win_event { Event::Window { win_event, .. } => match win_event {
WindowEvent::FocusGained | WindowEvent::Shown => {} WindowEvent::FocusGained | WindowEvent::Shown => {
WindowEvent::FocusLost | WindowEvent::Hidden => {} if state.settings.pause_on_focus_loss {
{
let mut mutex = GAME_SUSPENDED.lock().unwrap();
*mutex = false;
}
state.sound_manager.resume();
game.loops = 0;
}
}
WindowEvent::FocusLost | WindowEvent::Hidden => {
if state.settings.pause_on_focus_loss {
let mut mutex = GAME_SUSPENDED.lock().unwrap();
*mutex = true;
state.sound_manager.pause();
}
}
WindowEvent::SizeChanged(width, height) => { WindowEvent::SizeChanged(width, height) => {
ctx.screen_size = (width.max(1) as f32, height.max(1) as f32); ctx.screen_size = (width.max(1) as f32, height.max(1) as f32);

View file

@ -22,6 +22,7 @@ enum CurrentMenu {
SoundMenu, SoundMenu,
SoundtrackMenu, SoundtrackMenu,
LanguageMenu, LanguageMenu,
BehaviorMenu,
} }
#[derive(Debug, Clone, Copy, Eq, PartialEq)] #[derive(Debug, Clone, Copy, Eq, PartialEq)]
@ -29,7 +30,7 @@ enum MainMenuEntry {
Graphics, Graphics,
Sound, Sound,
Language, Language,
GameTiming, Behavior,
DiscordLink, DiscordLink,
Back, Back,
} }
@ -101,6 +102,19 @@ impl Default for LanguageMenuEntry {
} }
} }
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
enum BehaviorMenuEntry {
GameTiming,
PauseOnFocusLoss,
Back,
}
impl Default for BehaviorMenuEntry {
fn default() -> Self {
BehaviorMenuEntry::GameTiming
}
}
pub struct SettingsMenu { pub struct SettingsMenu {
current: CurrentMenu, current: CurrentMenu,
main: Menu<MainMenuEntry>, main: Menu<MainMenuEntry>,
@ -108,6 +122,7 @@ pub struct SettingsMenu {
sound: Menu<SoundMenuEntry>, sound: Menu<SoundMenuEntry>,
soundtrack: Menu<SoundtrackMenuEntry>, soundtrack: Menu<SoundtrackMenuEntry>,
language: Menu<LanguageMenuEntry>, language: Menu<LanguageMenuEntry>,
behavior: Menu<BehaviorMenuEntry>,
pub on_title: bool, pub on_title: bool,
} }
@ -120,8 +135,18 @@ impl SettingsMenu {
let sound = Menu::new(0, 0, 260, 0); let sound = Menu::new(0, 0, 260, 0);
let soundtrack = Menu::new(0, 0, 260, 0); let soundtrack = Menu::new(0, 0, 260, 0);
let language = Menu::new(0, 0, 120, 0); let language = Menu::new(0, 0, 120, 0);
let behavior = Menu::new(0, 0, 220, 0);
SettingsMenu { current: CurrentMenu::MainMenu, main, graphics, sound, soundtrack, language, on_title: false } SettingsMenu {
current: CurrentMenu::MainMenu,
main,
graphics,
sound,
soundtrack,
language,
behavior,
on_title: false,
}
} }
pub fn init(&mut self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult { pub fn init(&mut self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult {
@ -251,14 +276,7 @@ impl SettingsMenu {
self.main.push_entry(MainMenuEntry::Language, MenuEntry::Active(state.t("menus.options_menu.language"))); self.main.push_entry(MainMenuEntry::Language, MenuEntry::Active(state.t("menus.options_menu.language")));
} }
self.main.push_entry( self.main.push_entry(MainMenuEntry::Behavior, MenuEntry::Active(state.t("menus.options_menu.behavior")));
MainMenuEntry::GameTiming,
MenuEntry::Options(
state.t("menus.options_menu.game_timing.entry"),
if state.settings.timing_mode == TimingMode::_50Hz { 0 } else { 1 },
vec![state.t("menus.options_menu.game_timing.50tps"), state.t("menus.options_menu.game_timing.60tps")],
),
);
self.main.push_entry(MainMenuEntry::DiscordLink, MenuEntry::Active(DISCORD_LINK.to_owned())); self.main.push_entry(MainMenuEntry::DiscordLink, MenuEntry::Active(DISCORD_LINK.to_owned()));
@ -334,6 +352,28 @@ impl SettingsMenu {
self.soundtrack.push_entry(SoundtrackMenuEntry::Back, MenuEntry::Active(state.t("common.back"))); self.soundtrack.push_entry(SoundtrackMenuEntry::Back, MenuEntry::Active(state.t("common.back")));
self.behavior.push_entry(
BehaviorMenuEntry::GameTiming,
MenuEntry::Options(
state.t("menus.options_menu.behavior_menu.game_timing.entry"),
if state.settings.timing_mode == TimingMode::_50Hz { 0 } else { 1 },
vec![
state.t("menus.options_menu.behavior_menu.game_timing.50tps"),
state.t("menus.options_menu.behavior_menu.game_timing.60tps"),
],
),
);
self.behavior.push_entry(
BehaviorMenuEntry::PauseOnFocusLoss,
MenuEntry::Toggle(
state.t("menus.options_menu.behavior_menu.pause_on_focus_loss"),
state.settings.pause_on_focus_loss,
),
);
self.behavior.push_entry(BehaviorMenuEntry::Back, MenuEntry::Active(state.t("common.back")));
self.update_sizes(state); self.update_sizes(state);
Ok(()) Ok(())
@ -364,6 +404,11 @@ impl SettingsMenu {
self.language.update_height(); self.language.update_height();
self.language.x = ((state.canvas_size.0 - self.language.width as f32) / 2.0).floor() as isize; self.language.x = ((state.canvas_size.0 - self.language.width as f32) / 2.0).floor() as isize;
self.language.y = ((state.canvas_size.1 - self.language.height as f32) / 2.0).floor() as isize; self.language.y = ((state.canvas_size.1 - self.language.height as f32) / 2.0).floor() as isize;
self.behavior.update_width(state);
self.behavior.update_height();
self.behavior.x = ((state.canvas_size.0 - self.behavior.width as f32) / 2.0).floor() as isize;
self.behavior.y = 30 + ((state.canvas_size.1 - self.behavior.height as f32) / 2.0).floor() as isize;
} }
pub fn tick( pub fn tick(
@ -387,21 +432,8 @@ impl SettingsMenu {
self.language.selected = LanguageMenuEntry::Language(state.settings.locale); self.language.selected = LanguageMenuEntry::Language(state.settings.locale);
self.current = CurrentMenu::LanguageMenu; self.current = CurrentMenu::LanguageMenu;
} }
MenuSelectionResult::Selected(MainMenuEntry::GameTiming, toggle) => { MenuSelectionResult::Selected(MainMenuEntry::Behavior, _) => {
if let MenuEntry::Options(_, value, _) = toggle { self.current = CurrentMenu::BehaviorMenu;
match state.settings.timing_mode {
TimingMode::_50Hz => {
state.settings.timing_mode = TimingMode::_60Hz;
*value = 1;
}
TimingMode::_60Hz => {
state.settings.timing_mode = TimingMode::_50Hz;
*value = 0;
}
_ => {}
}
let _ = state.settings.save(ctx);
}
} }
MenuSelectionResult::Selected(MainMenuEntry::DiscordLink, _) => { MenuSelectionResult::Selected(MainMenuEntry::DiscordLink, _) => {
if let Err(e) = webbrowser::open(DISCORD_LINK) { if let Err(e) = webbrowser::open(DISCORD_LINK) {
@ -655,6 +687,36 @@ impl SettingsMenu {
} }
_ => (), _ => (),
}, },
CurrentMenu::BehaviorMenu => match self.behavior.tick(controller, state) {
MenuSelectionResult::Selected(BehaviorMenuEntry::GameTiming, toggle) => {
if let MenuEntry::Options(_, value, _) = toggle {
match state.settings.timing_mode {
TimingMode::_50Hz => {
state.settings.timing_mode = TimingMode::_60Hz;
*value = 1;
}
TimingMode::_60Hz => {
state.settings.timing_mode = TimingMode::_50Hz;
*value = 0;
}
_ => {}
}
let _ = state.settings.save(ctx);
}
}
MenuSelectionResult::Selected(BehaviorMenuEntry::PauseOnFocusLoss, toggle) => {
if let MenuEntry::Toggle(_, value) = toggle {
state.settings.pause_on_focus_loss = !state.settings.pause_on_focus_loss;
let _ = state.settings.save(ctx);
*value = state.settings.pause_on_focus_loss;
}
}
MenuSelectionResult::Selected(BehaviorMenuEntry::Back, _) | MenuSelectionResult::Canceled => {
self.current = CurrentMenu::MainMenu;
}
_ => (),
},
} }
Ok(()) Ok(())
} }
@ -666,6 +728,7 @@ impl SettingsMenu {
CurrentMenu::SoundMenu => self.sound.draw(state, ctx)?, CurrentMenu::SoundMenu => self.sound.draw(state, ctx)?,
CurrentMenu::SoundtrackMenu => self.soundtrack.draw(state, ctx)?, CurrentMenu::SoundtrackMenu => self.soundtrack.draw(state, ctx)?,
CurrentMenu::LanguageMenu => self.language.draw(state, ctx)?, CurrentMenu::LanguageMenu => self.language.draw(state, ctx)?,
CurrentMenu::BehaviorMenu => self.behavior.draw(state, ctx)?,
} }
Ok(()) Ok(())

View file

@ -24,6 +24,7 @@ pub struct JukeboxScene {
frame: Frame, frame: Frame,
stage: Stage, stage: Stage,
textures: StageTexturePaths, textures: StageTexturePaths,
previous_pause_on_focus_loss_setting: bool,
} }
impl JukeboxScene { impl JukeboxScene {
@ -58,6 +59,7 @@ impl JukeboxScene {
frame: Frame::new(), frame: Frame::new(),
stage: fake_stage, stage: fake_stage,
textures, textures,
previous_pause_on_focus_loss_setting: true,
} }
} }
} }
@ -97,6 +99,9 @@ impl Scene for JukeboxScene {
self.soundtracks.iter().position(|s| s == &state.settings.soundtrack).unwrap_or(0); self.soundtracks.iter().position(|s| s == &state.settings.soundtrack).unwrap_or(0);
self.selected_soundtrack = selected_soundtrack_index; self.selected_soundtrack = selected_soundtrack_index;
self.previous_pause_on_focus_loss_setting = state.settings.pause_on_focus_loss;
state.settings.pause_on_focus_loss = false;
Ok(()) Ok(())
} }
@ -151,6 +156,7 @@ impl Scene for JukeboxScene {
} }
if self.controller.trigger_back() { if self.controller.trigger_back() {
state.settings.pause_on_focus_loss = self.previous_pause_on_focus_loss_setting;
state.next_scene = Some(Box::new(TitleScene::new())); state.next_scene = Some(Box::new(TitleScene::new()));
} }

View file

@ -34,6 +34,8 @@ pub struct Settings {
pub sfx_volume: f32, pub sfx_volume: f32,
#[serde(default = "default_timing")] #[serde(default = "default_timing")]
pub timing_mode: TimingMode, pub timing_mode: TimingMode,
#[serde(default = "default_pause_on_focus_loss")]
pub pause_on_focus_loss: bool,
#[serde(default = "default_interpolation")] #[serde(default = "default_interpolation")]
pub organya_interpolation: InterpolationMode, pub organya_interpolation: InterpolationMode,
#[serde(default = "default_controller_type")] #[serde(default = "default_controller_type")]
@ -79,7 +81,7 @@ fn default_true() -> bool {
#[inline(always)] #[inline(always)]
fn current_version() -> u32 { fn current_version() -> u32 {
14 15
} }
#[inline(always)] #[inline(always)]
@ -127,6 +129,11 @@ fn default_controller_type() -> ControllerType {
ControllerType::Keyboard ControllerType::Keyboard
} }
#[inline(always)]
fn default_pause_on_focus_loss() -> bool {
true
}
impl Settings { impl Settings {
pub fn load(ctx: &Context) -> GameResult<Settings> { pub fn load(ctx: &Context) -> GameResult<Settings> {
if let Ok(file) = user_open(ctx, "/settings.json") { if let Ok(file) = user_open(ctx, "/settings.json") {
@ -223,6 +230,11 @@ impl Settings {
self.player2_controller_button_map = player_default_controller_button_map(); self.player2_controller_button_map = player_default_controller_button_map();
} }
if self.version == 14 {
self.version = 15;
self.pause_on_focus_loss = default_pause_on_focus_loss();
}
if self.version != initial_version { if self.version != initial_version {
log::info!("Upgraded configuration file from version {} to {}.", initial_version, self.version); log::info!("Upgraded configuration file from version {} to {}.", initial_version, self.version);
} }
@ -281,6 +293,7 @@ impl Default for Settings {
bgm_volume: 1.0, bgm_volume: 1.0,
sfx_volume: 1.0, sfx_volume: 1.0,
timing_mode: default_timing(), timing_mode: default_timing(),
pause_on_focus_loss: default_pause_on_focus_loss(),
organya_interpolation: InterpolationMode::Linear, organya_interpolation: InterpolationMode::Linear,
player1_controller_type: default_controller_type(), player1_controller_type: default_controller_type(),
player2_controller_type: default_controller_type(), player2_controller_type: default_controller_type(),