Merge branch '68-startscreen-settings-implementation' into 'dev'

StartScreen Settings implementation

See merge request softwaregrundprojekt/2025-2026/einzelprojekt/tutorium-moritz/bernroider-dominik/bernroider-dominik!43
This commit is contained in:
Dominik Bernroider
2025-12-11 13:02:30 +00:00
4 changed files with 179 additions and 13 deletions

View File

@@ -1,9 +1,11 @@
use crate::features::phase::components::TimerSettings;
use crate::prelude::*; use crate::prelude::*;
/// Markers for main menu UI. /// Markers for main menu UI.
#[derive(Component)] #[derive(Component)]
pub enum RootMarker { pub enum RootMarker {
MainMenu, MainMenu,
Settings,
} }
/// Buttons in the main menu. /// Buttons in the main menu.
@@ -13,3 +15,6 @@ pub enum ButtonType {
NewGame, NewGame,
Settings, Settings,
} }
#[derive(Resource, Default, Debug)]
pub struct StartScreenTimerSettings(pub Option<TimerSettings>);

View File

@@ -1,17 +1,30 @@
use crate::features::hud::components::{SettingsTimerInput, TimerType};
use crate::features::phase::components::TimerSettings;
use crate::features::savegame::ui::spawn_load_popup; use crate::features::savegame::ui::spawn_load_popup;
use crate::prelude::*; use crate::prelude::*;
use components::*; use components::*;
use ui::settings::open_settings_menu;
pub mod components; pub mod components;
pub mod ui;
/// Plugin for the main menu screen. /// Plugin for the main menu screen.
pub struct StartScreenPlugin; pub struct StartScreenPlugin;
impl Plugin for StartScreenPlugin { impl Plugin for StartScreenPlugin {
fn build(&self, app: &mut App) { fn build(&self, app: &mut App) {
app.init_resource::<StartScreenTimerSettings>();
app.add_systems(OnEnter(AppState::StartScreen), setup); app.add_systems(OnEnter(AppState::StartScreen), setup);
app.add_systems(OnExit(AppState::StartScreen), cleanup); app.add_systems(OnExit(AppState::StartScreen), cleanup);
app.add_systems(Update, menu.run_if(in_state(AppState::StartScreen))); app.add_systems(
Update,
(menu, handle_settings_buttons, update_timer_settings_display)
.run_if(in_state(AppState::StartScreen)),
);
app.add_systems(
PostUpdate,
apply_start_screen_settings.run_if(in_state(AppState::GameScreen)),
);
} }
} }
@@ -70,18 +83,18 @@ fn menu(
) { ) {
for (interaction, button_type) in &mut interaction_query { for (interaction, button_type) in &mut interaction_query {
match *interaction { match *interaction {
Interaction::Pressed => { Interaction::Pressed => match button_type {
match button_type { ButtonType::LoadGame => {
ButtonType::LoadGame => { spawn_load_popup(&mut commands);
spawn_load_popup(&mut commands); }
} ButtonType::NewGame => {
ButtonType::NewGame => { commands.insert_resource(SavegamePath::next());
commands.insert_resource(SavegamePath::next()); next_state.set(AppState::GameScreen);
next_state.set(AppState::GameScreen); }
} ButtonType::Settings => {
ButtonType::Settings => todo!(), open_settings_menu(&mut commands);
}; }
} },
_ => (), _ => (),
} }
} }
@@ -93,3 +106,79 @@ fn cleanup(mut commands: Commands, query: Query<Entity, With<RootMarker>>) {
commands.entity(entity).despawn(); commands.entity(entity).despawn();
} }
} }
/// Handles button interactions within the settings menu.
fn handle_settings_buttons(
mut interaction_query: Query<
(&Interaction, &crate::features::hud::components::ButtonType),
(Changed<Interaction>, With<Button>),
>,
mut timer_settings: ResMut<TimerSettings>,
mut ss_timer_settings: ResMut<StartScreenTimerSettings>,
keys: Res<ButtonInput<KeyCode>>,
) {
let shift_multiplier = if keys.any_pressed([KeyCode::ShiftLeft, KeyCode::ShiftRight]) {
10
} else {
1
};
for (interaction, button_type) in &mut interaction_query {
if *interaction == Interaction::Pressed {
if let crate::features::hud::components::ButtonType::SettingsTimerChange {
input,
amount,
} = button_type
{
match input {
SettingsTimerInput::Minutes(timer_type) => {
timer_settings.change(timer_type, 60 * amount * shift_multiplier)
}
SettingsTimerInput::Seconds(timer_type) => {
timer_settings.change(timer_type, *amount * shift_multiplier)
}
}
ss_timer_settings.0 = Some(timer_settings.clone());
}
}
}
}
/// Updates the timer settings display in the settings menu.
fn update_timer_settings_display(
timer_settings: Res<TimerSettings>,
mut query: Query<(&SettingsTimerInput, &mut Text)>,
) {
for (input_type, mut text) in query.iter_mut() {
match input_type {
SettingsTimerInput::Minutes(timer_type) => {
let value = match timer_type {
TimerType::Focus => timer_settings.focus_duration,
TimerType::ShortBreak => timer_settings.short_break_duration,
TimerType::LongBreak => timer_settings.long_break_duration,
} as f32;
text.0 = format!("{:0>2}", (value / 60.0).floor());
}
SettingsTimerInput::Seconds(timer_type) => {
let value = match timer_type {
TimerType::Focus => timer_settings.focus_duration,
TimerType::ShortBreak => timer_settings.short_break_duration,
TimerType::LongBreak => timer_settings.long_break_duration,
};
text.0 = format!("{:0>2}", (value % 60));
}
}
}
}
/// Applies the timer settings from the start screen once the game screen is entered.
fn apply_start_screen_settings(
mut settings: ResMut<TimerSettings>,
mut ss_settings: ResMut<StartScreenTimerSettings>,
) {
if let Some(new_settings) = ss_settings.0.take() {
*settings = new_settings;
}
}

View File

@@ -0,0 +1 @@
pub mod settings;

View File

@@ -0,0 +1,71 @@
use crate::features::hud::components::TimerType;
use crate::features::hud::ui::timer_settings::timer_settings;
use crate::features::start_screen::components::RootMarker;
use crate::prelude::*;
/// Spawns the settings popup for the start screen.
pub fn open_settings_menu(commands: &mut Commands) {
spawn_popup(
commands,
RootMarker::Settings,
"Einstellungen",
Node {
width: px(700),
..default()
},
|parent| {
parent.spawn((
Node {
justify_content: JustifyContent::Center,
..Node::hstack(px(30))
},
children![
(
Node {
width: percent(40),
..Node::vstack(px(10))
},
children![
text("Timer Einstellungen", 18.0, Color::WHITE),
text(
"Tipp: Benutze [Umschalt] um in 10er Schritten zu inkrementieren oder dekrementieren!",
16.0,
Color::WHITE
),
]
),
(
Node {
align_items: AlignItems::Center,
..Node::vstack(px(10))
},
children![
text("Fokus Phase", 12.0, Color::WHITE),
timer_settings(TimerType::Focus)
]
),
(
Node {
align_items: AlignItems::Center,
..Node::vstack(px(10))
},
children![
text("Kurze Pause", 12.0, Color::WHITE),
timer_settings(TimerType::ShortBreak)
]
),
(
Node {
align_items: AlignItems::Center,
..Node::vstack(px(10))
},
children![
text("Lange Pause", 12.0, Color::WHITE),
timer_settings(TimerType::LongBreak)
]
)
],
));
},
);
}