merge: Merge remote-tracking branch 'origin/dev' into 48-inventory
This commit is contained in:
@@ -9,10 +9,10 @@ impl Plugin for GameScreenPlugin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn setup(mut commands: Commands) {
|
fn setup(mut clear_color: ResMut<ClearColor>) {
|
||||||
commands.insert_resource(ClearColor(Color::srgb(0.294, 0.412, 0.184)));
|
*clear_color = ClearColor(Color::srgb(0.294, 0.412, 0.184));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cleanup(mut commands: Commands) {
|
fn cleanup(mut clear_color: ResMut<ClearColor>) {
|
||||||
commands.remove_resource::<ClearColor>();
|
*clear_color = ClearColor(Color::srgb(0.2, 0.2, 0.2));
|
||||||
}
|
}
|
||||||
|
|||||||
67
src/features/hud/components.rs
Normal file
67
src/features/hud/components.rs
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
use crate::{features::phase::components::TimerSettings, prelude::*};
|
||||||
|
|
||||||
|
#[derive(Component)]
|
||||||
|
pub enum RootMarker {
|
||||||
|
Status,
|
||||||
|
Settings,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Component)]
|
||||||
|
pub enum TextType {
|
||||||
|
Phase,
|
||||||
|
Timer,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Component)]
|
||||||
|
pub enum ButtonType {
|
||||||
|
SavegameDump,
|
||||||
|
SettingsOpen,
|
||||||
|
SettingsClose,
|
||||||
|
SettingsExit,
|
||||||
|
SettingsSave,
|
||||||
|
SettingsTimerChange {
|
||||||
|
input: SettingsTimerInput,
|
||||||
|
amount: i32,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub enum TimerType {
|
||||||
|
Focus,
|
||||||
|
ShortBreak,
|
||||||
|
LongBreak,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TimerSettings {
|
||||||
|
pub fn change(&mut self, timer_type: &TimerType, amount: i32) {
|
||||||
|
match timer_type {
|
||||||
|
TimerType::Focus => {
|
||||||
|
self.focus_duration = (self.focus_duration as i32 + amount) as u32;
|
||||||
|
if self.focus_duration > 7259 {
|
||||||
|
// 120:59
|
||||||
|
self.focus_duration = 7259;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TimerType::LongBreak => {
|
||||||
|
self.long_break_duration = (self.long_break_duration as i32 + amount) as u32;
|
||||||
|
if self.long_break_duration > 7259 {
|
||||||
|
// 120:59
|
||||||
|
self.long_break_duration = 7259;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TimerType::ShortBreak => {
|
||||||
|
self.short_break_duration = (self.short_break_duration as i32 + amount) as u32;
|
||||||
|
if self.short_break_duration > 7259 {
|
||||||
|
// 120:59
|
||||||
|
self.short_break_duration = 7259;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Component, Clone)]
|
||||||
|
pub enum SettingsTimerInput {
|
||||||
|
Minutes(TimerType),
|
||||||
|
Seconds(TimerType),
|
||||||
|
}
|
||||||
157
src/features/hud/mod.rs
Normal file
157
src/features/hud/mod.rs
Normal file
@@ -0,0 +1,157 @@
|
|||||||
|
use crate::features::phase::components::TimerSettings;
|
||||||
|
use crate::features::savegame::messages::SavegameDumpMessage;
|
||||||
|
use crate::prelude::*;
|
||||||
|
use components::*;
|
||||||
|
use ui::*;
|
||||||
|
|
||||||
|
pub mod components;
|
||||||
|
pub mod ui;
|
||||||
|
|
||||||
|
pub struct HudPlugin;
|
||||||
|
|
||||||
|
impl Plugin for HudPlugin {
|
||||||
|
fn build(&self, app: &mut App) {
|
||||||
|
app.add_systems(OnEnter(AppState::GameScreen), setup);
|
||||||
|
app.add_systems(OnExit(AppState::GameScreen), cleanup);
|
||||||
|
app.add_systems(
|
||||||
|
Update,
|
||||||
|
(update_status, buttons, update_timer_settings).run_if(in_state(AppState::GameScreen)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn setup(mut commands: Commands) {
|
||||||
|
commands.spawn((
|
||||||
|
RootMarker::Status,
|
||||||
|
Node {
|
||||||
|
position_type: PositionType::Absolute,
|
||||||
|
bottom: px(0),
|
||||||
|
left: px(0),
|
||||||
|
|
||||||
|
width: percent(100),
|
||||||
|
height: px(50),
|
||||||
|
|
||||||
|
justify_content: JustifyContent::SpaceAround,
|
||||||
|
align_items: AlignItems::Center,
|
||||||
|
flex_direction: FlexDirection::Row,
|
||||||
|
..default()
|
||||||
|
},
|
||||||
|
BackgroundColor(Color::srgba(0.0, 0.0, 0.0, 0.8)),
|
||||||
|
children![
|
||||||
|
(
|
||||||
|
TextType::Phase,
|
||||||
|
Text::new("..."),
|
||||||
|
TextFont::from_font_size(16.0),
|
||||||
|
TextColor(Color::WHITE)
|
||||||
|
),
|
||||||
|
(
|
||||||
|
TextType::Timer,
|
||||||
|
Text::new("--:--"),
|
||||||
|
TextFont::from_font_size(16.0),
|
||||||
|
TextColor(Color::WHITE)
|
||||||
|
),
|
||||||
|
(
|
||||||
|
Button,
|
||||||
|
ButtonType::SettingsOpen,
|
||||||
|
Node::default(),
|
||||||
|
children![
|
||||||
|
Text::new("Einstellungen"),
|
||||||
|
TextFont::from_font_size(16.0),
|
||||||
|
TextColor(Color::WHITE)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
],
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_status(phase_res: Res<CurrentPhase>, mut text_query: Query<(&mut Text, &TextType)>) {
|
||||||
|
if !phase_res.is_changed() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let current_phase = &phase_res.0;
|
||||||
|
|
||||||
|
for (mut text, status_type) in text_query.iter_mut() {
|
||||||
|
text.0 = match status_type {
|
||||||
|
TextType::Phase => current_phase.display_name().into(),
|
||||||
|
TextType::Timer => current_phase.format_duration(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn buttons(
|
||||||
|
mut commands: Commands,
|
||||||
|
mut interaction_query: Query<(&Interaction, &ButtonType), (Changed<Interaction>, With<Button>)>,
|
||||||
|
root_query: Query<(Entity, &RootMarker)>,
|
||||||
|
mut savegame_messages: MessageWriter<SavegameDumpMessage>,
|
||||||
|
mut next_state: ResMut<NextState<AppState>>,
|
||||||
|
mut timer_settings: ResMut<TimerSettings>,
|
||||||
|
) {
|
||||||
|
for (interaction, button_type) in &mut interaction_query {
|
||||||
|
match *interaction {
|
||||||
|
Interaction::Pressed => match button_type {
|
||||||
|
ButtonType::SettingsOpen => {
|
||||||
|
open_settings(&mut commands);
|
||||||
|
}
|
||||||
|
ButtonType::SettingsClose => {
|
||||||
|
for (entity, root) in root_query.iter() {
|
||||||
|
match *root {
|
||||||
|
RootMarker::Settings => commands.entity(entity).despawn(),
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ButtonType::SettingsExit => {
|
||||||
|
savegame_messages.write(SavegameDumpMessage);
|
||||||
|
next_state.set(AppState::StartScreen);
|
||||||
|
}
|
||||||
|
ButtonType::SettingsSave => {
|
||||||
|
savegame_messages.write(SavegameDumpMessage);
|
||||||
|
}
|
||||||
|
ButtonType::SettingsTimerChange { input, amount } => match input {
|
||||||
|
SettingsTimerInput::Minutes(timer_type) => {
|
||||||
|
timer_settings.change(timer_type, 60 * amount)
|
||||||
|
}
|
||||||
|
SettingsTimerInput::Seconds(timer_type) => {
|
||||||
|
timer_settings.change(timer_type, *amount)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => {}
|
||||||
|
},
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cleanup(mut commands: Commands, query: Query<Entity, With<RootMarker>>) {
|
||||||
|
for entity in query.iter() {
|
||||||
|
commands.entity(entity).despawn();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_timer_settings(
|
||||||
|
timer_settings: ResMut<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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
5
src/features/hud/ui/mod.rs
Normal file
5
src/features/hud/ui/mod.rs
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
pub mod settings;
|
||||||
|
pub mod timer_settings;
|
||||||
|
|
||||||
|
pub use settings::*;
|
||||||
|
pub use timer_settings::*;
|
||||||
182
src/features/hud/ui/settings.rs
Normal file
182
src/features/hud/ui/settings.rs
Normal file
@@ -0,0 +1,182 @@
|
|||||||
|
use super::super::components::*;
|
||||||
|
use super::timer_settings::timer_settings;
|
||||||
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
pub fn open_settings(commands: &mut Commands) {
|
||||||
|
commands
|
||||||
|
.spawn((
|
||||||
|
RootMarker::Settings,
|
||||||
|
Node {
|
||||||
|
position_type: PositionType::Absolute,
|
||||||
|
width: percent(100),
|
||||||
|
height: percent(100),
|
||||||
|
justify_content: JustifyContent::Center,
|
||||||
|
align_items: AlignItems::Center,
|
||||||
|
..default()
|
||||||
|
},
|
||||||
|
ZIndex(1),
|
||||||
|
BackgroundColor(Color::srgba(0.0, 0.0, 0.0, 0.8)),
|
||||||
|
))
|
||||||
|
.with_children(|parent| {
|
||||||
|
parent
|
||||||
|
.spawn((
|
||||||
|
Node {
|
||||||
|
flex_direction: FlexDirection::Column,
|
||||||
|
align_items: AlignItems::Center,
|
||||||
|
padding: UiRect::all(px(20.0)),
|
||||||
|
..default()
|
||||||
|
},
|
||||||
|
BackgroundColor(Color::srgb(0.2, 0.2, 0.2)),
|
||||||
|
BorderRadius::all(px(10.0)),
|
||||||
|
))
|
||||||
|
.with_children(|parent| {
|
||||||
|
parent.spawn((
|
||||||
|
Node {
|
||||||
|
width: percent(100.0),
|
||||||
|
justify_content: JustifyContent::SpaceBetween,
|
||||||
|
align_items: AlignItems::Center,
|
||||||
|
margin: UiRect::bottom(px(20.0)),
|
||||||
|
column_gap: px(20.0),
|
||||||
|
..default()
|
||||||
|
},
|
||||||
|
children![
|
||||||
|
(
|
||||||
|
Text::new("Spiel Einstellungen"),
|
||||||
|
TextFont::from_font_size(40.0),
|
||||||
|
TextColor(Color::WHITE),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
Button,
|
||||||
|
ButtonType::SettingsClose,
|
||||||
|
Node {
|
||||||
|
width: px(40.0),
|
||||||
|
height: px(40.0),
|
||||||
|
justify_content: JustifyContent::Center,
|
||||||
|
align_items: AlignItems::Center,
|
||||||
|
..default()
|
||||||
|
},
|
||||||
|
BackgroundColor(Color::srgb(0.8, 0.2, 0.2)),
|
||||||
|
BorderRadius::MAX,
|
||||||
|
children![(
|
||||||
|
Text::new("X"),
|
||||||
|
TextFont::from_font_size(24.0),
|
||||||
|
TextColor(Color::WHITE),
|
||||||
|
)]
|
||||||
|
)
|
||||||
|
],
|
||||||
|
));
|
||||||
|
|
||||||
|
parent
|
||||||
|
.spawn(Node {
|
||||||
|
width: percent(100),
|
||||||
|
flex_direction: FlexDirection::Column,
|
||||||
|
margin: UiRect::top(px(10.0)),
|
||||||
|
row_gap: px(10.0),
|
||||||
|
..default()
|
||||||
|
})
|
||||||
|
.with_children(|parent| {
|
||||||
|
parent.spawn((
|
||||||
|
Button,
|
||||||
|
ButtonType::SettingsExit,
|
||||||
|
Node {
|
||||||
|
width: percent(100),
|
||||||
|
height: px(80),
|
||||||
|
justify_content: JustifyContent::Center,
|
||||||
|
align_items: AlignItems::Center,
|
||||||
|
padding: UiRect::horizontal(px(10.0)),
|
||||||
|
..default()
|
||||||
|
},
|
||||||
|
BackgroundColor(NORMAL_BUTTON),
|
||||||
|
BorderRadius::all(px(10)),
|
||||||
|
children![(
|
||||||
|
Text::new("Spiel verlassen"),
|
||||||
|
TextFont::from_font_size(24.0),
|
||||||
|
TextColor(Color::WHITE)
|
||||||
|
)],
|
||||||
|
));
|
||||||
|
|
||||||
|
parent.spawn((
|
||||||
|
Button,
|
||||||
|
ButtonType::SettingsSave,
|
||||||
|
Node {
|
||||||
|
width: percent(100),
|
||||||
|
height: px(80),
|
||||||
|
justify_content: JustifyContent::Center,
|
||||||
|
align_items: AlignItems::Center,
|
||||||
|
padding: UiRect::horizontal(px(10.0)),
|
||||||
|
..default()
|
||||||
|
},
|
||||||
|
BackgroundColor(NORMAL_BUTTON),
|
||||||
|
BorderRadius::all(px(10)),
|
||||||
|
children![(
|
||||||
|
Text::new("Spiel speichern"),
|
||||||
|
TextFont::from_font_size(24.0),
|
||||||
|
TextColor(Color::WHITE)
|
||||||
|
)],
|
||||||
|
));
|
||||||
|
|
||||||
|
parent.spawn((
|
||||||
|
Node {
|
||||||
|
width: percent(100),
|
||||||
|
flex_direction: FlexDirection::Row,
|
||||||
|
justify_content: JustifyContent::SpaceBetween,
|
||||||
|
align_items: AlignItems::Center,
|
||||||
|
column_gap: px(10),
|
||||||
|
padding: UiRect::horizontal(px(10.0)),
|
||||||
|
..default()
|
||||||
|
},
|
||||||
|
children![
|
||||||
|
(
|
||||||
|
Node {
|
||||||
|
flex_direction: FlexDirection::Column,
|
||||||
|
align_items: AlignItems::Center,
|
||||||
|
row_gap: px(10),
|
||||||
|
..default()
|
||||||
|
},
|
||||||
|
children![
|
||||||
|
(
|
||||||
|
Text::new("Fokus Phase"),
|
||||||
|
TextFont::from_font_size(12.0),
|
||||||
|
TextColor(Color::WHITE)
|
||||||
|
),
|
||||||
|
timer_settings(TimerType::Focus)
|
||||||
|
]
|
||||||
|
),
|
||||||
|
(
|
||||||
|
Node {
|
||||||
|
flex_direction: FlexDirection::Column,
|
||||||
|
align_items: AlignItems::Center,
|
||||||
|
row_gap: px(10),
|
||||||
|
..default()
|
||||||
|
},
|
||||||
|
children![
|
||||||
|
(
|
||||||
|
Text::new("Kurze Pause"),
|
||||||
|
TextFont::from_font_size(12.0),
|
||||||
|
TextColor(Color::WHITE)
|
||||||
|
),
|
||||||
|
timer_settings(TimerType::ShortBreak)
|
||||||
|
]
|
||||||
|
),
|
||||||
|
(
|
||||||
|
Node {
|
||||||
|
flex_direction: FlexDirection::Column,
|
||||||
|
align_items: AlignItems::Center,
|
||||||
|
row_gap: px(10),
|
||||||
|
..default()
|
||||||
|
},
|
||||||
|
children![
|
||||||
|
(
|
||||||
|
Text::new("Lange Pause"),
|
||||||
|
TextFont::from_font_size(12.0),
|
||||||
|
TextColor(Color::WHITE)
|
||||||
|
),
|
||||||
|
timer_settings(TimerType::LongBreak)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
],
|
||||||
|
));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
74
src/features/hud/ui/timer_settings.rs
Normal file
74
src/features/hud/ui/timer_settings.rs
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
use super::super::components::*;
|
||||||
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
pub fn timer_settings(timer_type: TimerType) -> impl Bundle {
|
||||||
|
(
|
||||||
|
Node {
|
||||||
|
flex_direction: FlexDirection::Row,
|
||||||
|
align_items: AlignItems::Center,
|
||||||
|
..default()
|
||||||
|
},
|
||||||
|
children![
|
||||||
|
timer_settings_part(SettingsTimerInput::Minutes(timer_type.clone()), 1),
|
||||||
|
(
|
||||||
|
Text::new(":"),
|
||||||
|
TextFont::from_font_size(24.0),
|
||||||
|
TextColor(Color::WHITE)
|
||||||
|
),
|
||||||
|
timer_settings_part(SettingsTimerInput::Seconds(timer_type.clone()), 1),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn timer_settings_part(input: SettingsTimerInput, amount: u32) -> impl Bundle {
|
||||||
|
(
|
||||||
|
Node {
|
||||||
|
flex_direction: FlexDirection::Column,
|
||||||
|
..default()
|
||||||
|
},
|
||||||
|
children![
|
||||||
|
(
|
||||||
|
Button,
|
||||||
|
ButtonType::SettingsTimerChange {
|
||||||
|
input: input.clone(),
|
||||||
|
amount: amount as i32
|
||||||
|
},
|
||||||
|
Node {
|
||||||
|
width: auto(),
|
||||||
|
justify_content: JustifyContent::Center,
|
||||||
|
..default()
|
||||||
|
},
|
||||||
|
BackgroundColor(NORMAL_BUTTON),
|
||||||
|
children![
|
||||||
|
Text::new("+"),
|
||||||
|
TextFont::from_font_size(12.0),
|
||||||
|
TextColor(Color::WHITE)
|
||||||
|
]
|
||||||
|
),
|
||||||
|
(
|
||||||
|
input.clone(),
|
||||||
|
Text::new("--"),
|
||||||
|
TextFont::from_font_size(24.0),
|
||||||
|
TextColor(Color::WHITE)
|
||||||
|
),
|
||||||
|
(
|
||||||
|
Button,
|
||||||
|
ButtonType::SettingsTimerChange {
|
||||||
|
input: input.clone(),
|
||||||
|
amount: -(amount as i32),
|
||||||
|
},
|
||||||
|
Node {
|
||||||
|
width: auto(),
|
||||||
|
justify_content: JustifyContent::Center,
|
||||||
|
..default()
|
||||||
|
},
|
||||||
|
BackgroundColor(NORMAL_BUTTON),
|
||||||
|
children![
|
||||||
|
Text::new("-"),
|
||||||
|
TextFont::from_font_size(12.0),
|
||||||
|
TextColor(Color::WHITE)
|
||||||
|
]
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -2,23 +2,23 @@ pub mod config;
|
|||||||
pub mod core;
|
pub mod core;
|
||||||
pub mod game_screen;
|
pub mod game_screen;
|
||||||
pub mod grid;
|
pub mod grid;
|
||||||
|
pub mod hud;
|
||||||
pub mod input;
|
pub mod input;
|
||||||
pub mod inventory;
|
pub mod inventory;
|
||||||
pub mod phase;
|
pub mod phase;
|
||||||
pub mod pom;
|
pub mod pom;
|
||||||
pub mod savegame;
|
pub mod savegame;
|
||||||
pub mod start_screen;
|
pub mod start_screen;
|
||||||
pub mod status;
|
|
||||||
pub mod ui;
|
pub mod ui;
|
||||||
|
|
||||||
pub use core::CorePlugin;
|
pub use core::CorePlugin;
|
||||||
pub use game_screen::GameScreenPlugin;
|
pub use game_screen::GameScreenPlugin;
|
||||||
pub use grid::GridPlugin;
|
pub use grid::GridPlugin;
|
||||||
|
pub use hud::HudPlugin;
|
||||||
pub use input::InputPlugin;
|
pub use input::InputPlugin;
|
||||||
pub use inventory::InventoryPlugin;
|
pub use inventory::InventoryPlugin;
|
||||||
pub use phase::PhasePlugin;
|
pub use phase::PhasePlugin;
|
||||||
pub use pom::PomPlugin;
|
pub use pom::PomPlugin;
|
||||||
pub use savegame::SavegamePlugin;
|
pub use savegame::SavegamePlugin;
|
||||||
pub use start_screen::StartScreenPlugin;
|
pub use start_screen::StartScreenPlugin;
|
||||||
pub use status::StatusPlugin;
|
|
||||||
pub use ui::UiPlugin;
|
pub use ui::UiPlugin;
|
||||||
|
|||||||
@@ -42,18 +42,18 @@ pub struct CurrentPhase(pub Phase);
|
|||||||
|
|
||||||
#[derive(Resource, Debug, Serialize, Deserialize, Clone)]
|
#[derive(Resource, Debug, Serialize, Deserialize, Clone)]
|
||||||
pub struct TimerSettings {
|
pub struct TimerSettings {
|
||||||
pub focus_duration: f32,
|
pub focus_duration: u32,
|
||||||
pub short_break_duration: f32,
|
pub short_break_duration: u32,
|
||||||
pub long_break_duration: f32,
|
pub long_break_duration: u32,
|
||||||
pub long_break_interval: u32,
|
pub long_break_interval: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for TimerSettings {
|
impl Default for TimerSettings {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
focus_duration: 25.0 * 60.0,
|
focus_duration: 25 * 60,
|
||||||
short_break_duration: 5.0 * 60.0,
|
short_break_duration: 5 * 60,
|
||||||
long_break_duration: 15.0 * 60.0,
|
long_break_duration: 15 * 60,
|
||||||
long_break_interval: 4,
|
long_break_interval: 4,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ fn load_rules(mut phase_res: ResMut<CurrentPhase>, settings: Res<TimerSettings>)
|
|||||||
|
|
||||||
let new_phase = match phase {
|
let new_phase = match phase {
|
||||||
Phase::Focus { .. } => Some(Phase::Focus {
|
Phase::Focus { .. } => Some(Phase::Focus {
|
||||||
duration: settings.focus_duration,
|
duration: settings.focus_duration as f32,
|
||||||
}),
|
}),
|
||||||
Phase::Break { .. } => Some(Phase::Break { duration: 0.0 }),
|
Phase::Break { .. } => Some(Phase::Break { duration: 0.0 }),
|
||||||
_ => None,
|
_ => None,
|
||||||
@@ -141,11 +141,11 @@ fn handle_continue(
|
|||||||
|
|
||||||
if is_long_break {
|
if is_long_break {
|
||||||
*phase = Phase::Break {
|
*phase = Phase::Break {
|
||||||
duration: settings.long_break_duration,
|
duration: settings.long_break_duration as f32,
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
*phase = Phase::Break {
|
*phase = Phase::Break {
|
||||||
duration: settings.short_break_duration,
|
duration: settings.short_break_duration as f32,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +0,0 @@
|
|||||||
use crate::prelude::*;
|
|
||||||
|
|
||||||
pub const NORMAL_BUTTON: Color = Color::srgb(0.15, 0.15, 0.15);
|
|
||||||
pub const HOVERED_BUTTON: Color = Color::srgb(0.25, 0.25, 0.25);
|
|
||||||
pub const PRESSED_BUTTON: Color = Color::srgb(0.35, 0.75, 0.35);
|
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
use crate::{features::savegame::messages::SavegameLoadMessage, prelude::*};
|
use crate::{features::savegame::messages::SavegameLoadMessage, prelude::*};
|
||||||
use components::*;
|
use components::*;
|
||||||
use consts::*;
|
use ui::*;
|
||||||
|
|
||||||
pub mod components;
|
pub mod components;
|
||||||
pub mod consts;
|
pub mod ui;
|
||||||
|
|
||||||
pub struct StartScreenPlugin;
|
pub struct StartScreenPlugin;
|
||||||
|
|
||||||
@@ -87,152 +87,6 @@ fn setup(mut commands: Commands) {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn spawn_load_popup(commands: &mut Commands) {
|
|
||||||
commands
|
|
||||||
.spawn((
|
|
||||||
RootMarker::PopupSavegameLoad,
|
|
||||||
Node {
|
|
||||||
position_type: PositionType::Absolute,
|
|
||||||
width: percent(100),
|
|
||||||
height: percent(100),
|
|
||||||
justify_content: JustifyContent::Center,
|
|
||||||
align_items: AlignItems::Center,
|
|
||||||
..default()
|
|
||||||
},
|
|
||||||
ZIndex(1),
|
|
||||||
BackgroundColor(Color::srgba(0.0, 0.0, 0.0, 0.8)),
|
|
||||||
))
|
|
||||||
.with_children(|parent| {
|
|
||||||
parent
|
|
||||||
.spawn((
|
|
||||||
Node {
|
|
||||||
width: px(600.0),
|
|
||||||
height: px(500.0),
|
|
||||||
flex_direction: FlexDirection::Column,
|
|
||||||
align_items: AlignItems::Center,
|
|
||||||
padding: UiRect::all(px(20.0)),
|
|
||||||
..default()
|
|
||||||
},
|
|
||||||
BackgroundColor(Color::srgb(0.2, 0.2, 0.2)),
|
|
||||||
BorderRadius::all(Val::Px(10.0)),
|
|
||||||
))
|
|
||||||
.with_children(|parent| {
|
|
||||||
parent.spawn((
|
|
||||||
Node {
|
|
||||||
width: percent(100.0),
|
|
||||||
justify_content: JustifyContent::SpaceBetween,
|
|
||||||
align_items: AlignItems::Center,
|
|
||||||
margin: UiRect::bottom(px(20.0)),
|
|
||||||
..default()
|
|
||||||
},
|
|
||||||
children![
|
|
||||||
(
|
|
||||||
Text::new("Spielstand Auswahl"),
|
|
||||||
TextFont::from_font_size(40.0),
|
|
||||||
TextColor(Color::WHITE),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
Button,
|
|
||||||
ButtonType::PopupClose,
|
|
||||||
Node {
|
|
||||||
width: px(40.0),
|
|
||||||
height: px(40.0),
|
|
||||||
justify_content: JustifyContent::Center,
|
|
||||||
align_items: AlignItems::Center,
|
|
||||||
..default()
|
|
||||||
},
|
|
||||||
BackgroundColor(Color::srgb(0.8, 0.2, 0.2)),
|
|
||||||
children![(
|
|
||||||
Text::new("X"),
|
|
||||||
TextFont::from_font_size(24.0),
|
|
||||||
TextColor(Color::WHITE),
|
|
||||||
)]
|
|
||||||
)
|
|
||||||
],
|
|
||||||
));
|
|
||||||
|
|
||||||
parent
|
|
||||||
.spawn(Node {
|
|
||||||
width: percent(100),
|
|
||||||
flex_direction: FlexDirection::Column,
|
|
||||||
overflow: Overflow::scroll_y(),
|
|
||||||
margin: UiRect::all(px(20.0)),
|
|
||||||
row_gap: px(10.0),
|
|
||||||
..default()
|
|
||||||
})
|
|
||||||
.with_children(|parent| {
|
|
||||||
for savegame in SavegamePath::list() {
|
|
||||||
parent.spawn((
|
|
||||||
Button,
|
|
||||||
ButtonType::PopupSavegameLoad {
|
|
||||||
savegame_path: savegame.path.clone(),
|
|
||||||
},
|
|
||||||
Node {
|
|
||||||
width: percent(100),
|
|
||||||
height: px(80),
|
|
||||||
justify_content: JustifyContent::Center,
|
|
||||||
align_items: AlignItems::Center,
|
|
||||||
flex_direction: FlexDirection::Row,
|
|
||||||
column_gap: px(10.0),
|
|
||||||
padding: UiRect::horizontal(px(10.0)),
|
|
||||||
..default()
|
|
||||||
},
|
|
||||||
BackgroundColor(NORMAL_BUTTON),
|
|
||||||
children![
|
|
||||||
(
|
|
||||||
Node {
|
|
||||||
width: percent(100),
|
|
||||||
height: percent(100),
|
|
||||||
flex_direction: FlexDirection::Column,
|
|
||||||
justify_content: JustifyContent::Center,
|
|
||||||
..default()
|
|
||||||
},
|
|
||||||
children![
|
|
||||||
(
|
|
||||||
Text::new(format!(
|
|
||||||
"Spielstand {}",
|
|
||||||
savegame.index + 1
|
|
||||||
)),
|
|
||||||
TextFont::from_font_size(24.0),
|
|
||||||
TextColor(Color::srgb(0.9, 0.9, 0.9))
|
|
||||||
),
|
|
||||||
(
|
|
||||||
Text::new(format!(
|
|
||||||
"Beeren: {}, Fokusphasen abgeschlossen: {}",
|
|
||||||
savegame.total_berries,
|
|
||||||
savegame.completed_focus
|
|
||||||
)),
|
|
||||||
TextFont::from_font_size(18.0),
|
|
||||||
TextColor(Color::srgb(0.9, 0.9, 0.9))
|
|
||||||
)
|
|
||||||
]
|
|
||||||
),
|
|
||||||
(
|
|
||||||
Button,
|
|
||||||
ButtonType::PopupSavegameDelete {
|
|
||||||
savegame_path: savegame.path.clone()
|
|
||||||
},
|
|
||||||
Node {
|
|
||||||
width: px(40.0),
|
|
||||||
height: px(40.0),
|
|
||||||
justify_content: JustifyContent::Center,
|
|
||||||
align_items: AlignItems::Center,
|
|
||||||
..default()
|
|
||||||
},
|
|
||||||
children![(
|
|
||||||
Text::new("X"),
|
|
||||||
TextFont::from_font_size(24.0),
|
|
||||||
TextColor(Color::srgb(0.9, 0.9, 0.9))
|
|
||||||
)]
|
|
||||||
)
|
|
||||||
],
|
|
||||||
));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
fn menu(
|
fn menu(
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
mut next_state: ResMut<NextState<AppState>>,
|
mut next_state: ResMut<NextState<AppState>>,
|
||||||
|
|||||||
148
src/features/start_screen/ui/load.rs
Normal file
148
src/features/start_screen/ui/load.rs
Normal file
@@ -0,0 +1,148 @@
|
|||||||
|
use super::super::components::*;
|
||||||
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
pub fn spawn_load_popup(commands: &mut Commands) {
|
||||||
|
commands
|
||||||
|
.spawn((
|
||||||
|
RootMarker::PopupSavegameLoad,
|
||||||
|
Node {
|
||||||
|
position_type: PositionType::Absolute,
|
||||||
|
width: percent(100),
|
||||||
|
height: percent(100),
|
||||||
|
justify_content: JustifyContent::Center,
|
||||||
|
align_items: AlignItems::Center,
|
||||||
|
..default()
|
||||||
|
},
|
||||||
|
ZIndex(1),
|
||||||
|
BackgroundColor(Color::srgba(0.0, 0.0, 0.0, 0.8)),
|
||||||
|
))
|
||||||
|
.with_children(|parent| {
|
||||||
|
parent
|
||||||
|
.spawn((
|
||||||
|
Node {
|
||||||
|
width: px(600.0),
|
||||||
|
height: px(500.0),
|
||||||
|
flex_direction: FlexDirection::Column,
|
||||||
|
align_items: AlignItems::Center,
|
||||||
|
padding: UiRect::all(px(20.0)),
|
||||||
|
..default()
|
||||||
|
},
|
||||||
|
BackgroundColor(Color::srgb(0.2, 0.2, 0.2)),
|
||||||
|
BorderRadius::all(Val::Px(10.0)),
|
||||||
|
))
|
||||||
|
.with_children(|parent| {
|
||||||
|
parent.spawn((
|
||||||
|
Node {
|
||||||
|
width: percent(100.0),
|
||||||
|
justify_content: JustifyContent::SpaceBetween,
|
||||||
|
align_items: AlignItems::Center,
|
||||||
|
margin: UiRect::bottom(px(20.0)),
|
||||||
|
..default()
|
||||||
|
},
|
||||||
|
children![
|
||||||
|
(
|
||||||
|
Text::new("Spielstand Auswahl"),
|
||||||
|
TextFont::from_font_size(40.0),
|
||||||
|
TextColor(Color::WHITE),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
Button,
|
||||||
|
ButtonType::PopupClose,
|
||||||
|
Node {
|
||||||
|
width: px(40.0),
|
||||||
|
height: px(40.0),
|
||||||
|
justify_content: JustifyContent::Center,
|
||||||
|
align_items: AlignItems::Center,
|
||||||
|
..default()
|
||||||
|
},
|
||||||
|
BackgroundColor(Color::srgb(0.8, 0.2, 0.2)),
|
||||||
|
children![(
|
||||||
|
Text::new("X"),
|
||||||
|
TextFont::from_font_size(24.0),
|
||||||
|
TextColor(Color::WHITE),
|
||||||
|
)]
|
||||||
|
)
|
||||||
|
],
|
||||||
|
));
|
||||||
|
|
||||||
|
parent
|
||||||
|
.spawn(Node {
|
||||||
|
width: percent(100),
|
||||||
|
flex_direction: FlexDirection::Column,
|
||||||
|
overflow: Overflow::scroll_y(),
|
||||||
|
margin: UiRect::all(px(20.0)),
|
||||||
|
row_gap: px(10.0),
|
||||||
|
..default()
|
||||||
|
})
|
||||||
|
.with_children(|parent| {
|
||||||
|
for savegame in SavegamePath::list() {
|
||||||
|
parent.spawn((
|
||||||
|
Button,
|
||||||
|
ButtonType::PopupSavegameLoad {
|
||||||
|
savegame_path: savegame.path.clone(),
|
||||||
|
},
|
||||||
|
Node {
|
||||||
|
width: percent(100),
|
||||||
|
height: px(80),
|
||||||
|
justify_content: JustifyContent::Center,
|
||||||
|
align_items: AlignItems::Center,
|
||||||
|
flex_direction: FlexDirection::Row,
|
||||||
|
column_gap: px(10.0),
|
||||||
|
padding: UiRect::horizontal(px(10.0)),
|
||||||
|
..default()
|
||||||
|
},
|
||||||
|
BackgroundColor(NORMAL_BUTTON),
|
||||||
|
children![
|
||||||
|
(
|
||||||
|
Node {
|
||||||
|
width: percent(100),
|
||||||
|
height: percent(100),
|
||||||
|
flex_direction: FlexDirection::Column,
|
||||||
|
justify_content: JustifyContent::Center,
|
||||||
|
..default()
|
||||||
|
},
|
||||||
|
children![
|
||||||
|
(
|
||||||
|
Text::new(format!(
|
||||||
|
"Spielstand {}",
|
||||||
|
savegame.index + 1
|
||||||
|
)),
|
||||||
|
TextFont::from_font_size(24.0),
|
||||||
|
TextColor(Color::srgb(0.9, 0.9, 0.9))
|
||||||
|
),
|
||||||
|
(
|
||||||
|
Text::new(format!(
|
||||||
|
"Beeren: {}, Fokusphasen abgeschlossen: {}",
|
||||||
|
savegame.total_berries,
|
||||||
|
savegame.completed_focus
|
||||||
|
)),
|
||||||
|
TextFont::from_font_size(18.0),
|
||||||
|
TextColor(Color::srgb(0.9, 0.9, 0.9))
|
||||||
|
)
|
||||||
|
]
|
||||||
|
),
|
||||||
|
(
|
||||||
|
Button,
|
||||||
|
ButtonType::PopupSavegameDelete {
|
||||||
|
savegame_path: savegame.path.clone()
|
||||||
|
},
|
||||||
|
Node {
|
||||||
|
width: px(40.0),
|
||||||
|
height: px(40.0),
|
||||||
|
justify_content: JustifyContent::Center,
|
||||||
|
align_items: AlignItems::Center,
|
||||||
|
..default()
|
||||||
|
},
|
||||||
|
children![(
|
||||||
|
Text::new("X"),
|
||||||
|
TextFont::from_font_size(24.0),
|
||||||
|
TextColor(Color::srgb(0.9, 0.9, 0.9))
|
||||||
|
)]
|
||||||
|
)
|
||||||
|
],
|
||||||
|
));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
3
src/features/start_screen/ui/mod.rs
Normal file
3
src/features/start_screen/ui/mod.rs
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
pub mod load;
|
||||||
|
|
||||||
|
pub use load::*;
|
||||||
@@ -1,99 +0,0 @@
|
|||||||
use crate::features::savegame::messages::SavegameDumpMessage;
|
|
||||||
use crate::prelude::*;
|
|
||||||
|
|
||||||
pub struct StatusPlugin;
|
|
||||||
|
|
||||||
impl Plugin for StatusPlugin {
|
|
||||||
fn build(&self, app: &mut App) {
|
|
||||||
app.add_systems(OnEnter(AppState::GameScreen), setup);
|
|
||||||
app.add_systems(OnExit(AppState::GameScreen), cleanup);
|
|
||||||
app.add_systems(Update, update_status.run_if(in_state(AppState::GameScreen)));
|
|
||||||
app.add_systems(
|
|
||||||
Update,
|
|
||||||
status_buttons.run_if(in_state(AppState::GameScreen)),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn setup(mut commands: Commands) {
|
|
||||||
commands.spawn((
|
|
||||||
UiStatusRootContainer,
|
|
||||||
Node {
|
|
||||||
position_type: PositionType::Absolute,
|
|
||||||
bottom: px(0),
|
|
||||||
left: px(0),
|
|
||||||
|
|
||||||
width: percent(100),
|
|
||||||
height: px(50),
|
|
||||||
|
|
||||||
justify_content: JustifyContent::SpaceAround,
|
|
||||||
align_items: AlignItems::Center,
|
|
||||||
flex_direction: FlexDirection::Row,
|
|
||||||
..default()
|
|
||||||
},
|
|
||||||
BackgroundColor(Color::srgba(0.0, 0.0, 0.0, 0.8)),
|
|
||||||
children![
|
|
||||||
(
|
|
||||||
UiStatusText::Phase,
|
|
||||||
Text::new("..."),
|
|
||||||
TextFont::from_font_size(16.0),
|
|
||||||
TextColor(Color::WHITE)
|
|
||||||
),
|
|
||||||
(
|
|
||||||
UiStatusText::Timer,
|
|
||||||
Text::new("--:--"),
|
|
||||||
TextFont::from_font_size(16.0),
|
|
||||||
TextColor(Color::WHITE)
|
|
||||||
),
|
|
||||||
(
|
|
||||||
Button,
|
|
||||||
UiStatusButton::SavegameDump,
|
|
||||||
Node::default(),
|
|
||||||
children![
|
|
||||||
Text::new("Save"),
|
|
||||||
TextFont::from_font_size(16.0),
|
|
||||||
TextColor(Color::WHITE)
|
|
||||||
]
|
|
||||||
)
|
|
||||||
],
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn update_status(phase_res: Res<CurrentPhase>, mut text_query: Query<(&mut Text, &UiStatusText)>) {
|
|
||||||
if !phase_res.is_changed() {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let current_phase = &phase_res.0;
|
|
||||||
|
|
||||||
for (mut text, status_type) in text_query.iter_mut() {
|
|
||||||
text.0 = match status_type {
|
|
||||||
UiStatusText::Phase => current_phase.display_name().into(),
|
|
||||||
UiStatusText::Timer => current_phase.format_duration(),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn status_buttons(
|
|
||||||
mut interaction_query: Query<
|
|
||||||
(&Interaction, &UiStatusButton),
|
|
||||||
(Changed<Interaction>, With<Button>),
|
|
||||||
>,
|
|
||||||
mut savegamedump_messages: MessageWriter<SavegameDumpMessage>,
|
|
||||||
) {
|
|
||||||
for (interaction, button_type) in &mut interaction_query {
|
|
||||||
match *interaction {
|
|
||||||
Interaction::Pressed => match button_type {
|
|
||||||
UiStatusButton::SavegameDump => {
|
|
||||||
savegamedump_messages.write(SavegameDumpMessage);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn cleanup(mut commands: Commands, query: Query<Entity, With<UiStatusRootContainer>>) {
|
|
||||||
for entity in query.iter() {
|
|
||||||
commands.entity(entity).despawn();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -6,17 +6,3 @@ pub struct Scroll {
|
|||||||
pub entity: Entity,
|
pub entity: Entity,
|
||||||
pub delta: Vec2,
|
pub delta: Vec2,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Component)]
|
|
||||||
pub struct UiStatusRootContainer;
|
|
||||||
|
|
||||||
#[derive(Component)]
|
|
||||||
pub enum UiStatusText {
|
|
||||||
Phase,
|
|
||||||
Timer,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Component)]
|
|
||||||
pub enum UiStatusButton {
|
|
||||||
SavegameDump,
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1 +1,6 @@
|
|||||||
|
use crate::prelude::*;
|
||||||
|
|
||||||
pub const LINE_HEIGHT: f32 = 21.0;
|
pub const LINE_HEIGHT: f32 = 21.0;
|
||||||
|
pub const NORMAL_BUTTON: Color = Color::srgb(0.15, 0.15, 0.15);
|
||||||
|
pub const HOVERED_BUTTON: Color = Color::srgb(0.25, 0.25, 0.25);
|
||||||
|
pub const PRESSED_BUTTON: Color = Color::srgb(0.35, 0.75, 0.35);
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ fn main() {
|
|||||||
features::PomPlugin,
|
features::PomPlugin,
|
||||||
features::InputPlugin,
|
features::InputPlugin,
|
||||||
features::PhasePlugin,
|
features::PhasePlugin,
|
||||||
features::StatusPlugin,
|
features::HudPlugin,
|
||||||
features::SavegamePlugin,
|
features::SavegamePlugin,
|
||||||
features::UiPlugin,
|
features::UiPlugin,
|
||||||
features::InventoryPlugin,
|
features::InventoryPlugin,
|
||||||
|
|||||||
@@ -14,10 +14,7 @@ pub use crate::features::{
|
|||||||
messages::{InteractStartMessage, MoveMessage},
|
messages::{InteractStartMessage, MoveMessage},
|
||||||
},
|
},
|
||||||
savegame::components::SavegamePath,
|
savegame::components::SavegamePath,
|
||||||
ui::{
|
ui::consts::*,
|
||||||
components::{UiStatusButton, UiStatusRootContainer, UiStatusText},
|
|
||||||
consts::*,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
pub use crate::utils::path::get_internal_path;
|
pub use crate::utils::path::get_internal_path;
|
||||||
pub use bevy::prelude::*;
|
pub use bevy::prelude::*;
|
||||||
|
|||||||
Reference in New Issue
Block a user