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:
parent
2a792db797
commit
fee63f2600
|
|
@ -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:"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -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": "フォーカスが外れた時のポーズ:"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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(())
|
||||||
|
|
|
||||||
|
|
@ -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()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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(),
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue