yuno/src/menu.rs
silvana ff9950a89d
All checks were successful
ci/woodpecker/pr/fmt Pipeline was successful
ci/woodpecker/pr/clippy Pipeline was successful
ci/woodpecker/pr/test Pipeline was successful
Add(yuno): base project.
2024-08-04 09:28:54 +02:00

220 lines
7.5 KiB
Rust

use bevy::prelude::*;
use crate::{loading::TextureAssets, GameState};
pub struct MenuPlugin;
impl Plugin for MenuPlugin {
fn build(&self, app: &mut App) {
app.add_systems(OnEnter(GameState::Menu), setup)
.add_systems(Update, click_button.run_if(in_state(GameState::Menu)))
.add_systems(OnExit(GameState::Menu), cleanup);
}
}
#[derive(Component)]
struct ButtonColours {
normal: Color,
hovered: Color,
}
impl Default for ButtonColours {
fn default() -> Self {
Self {
normal: Color::srgb(88.0 / 255.0, 91.0 / 255.0, 112.0 / 255.0),
hovered: Color::srgb(116.0 / 255.0, 199.0 / 255.0, 236.0 / 255.0),
}
}
}
#[derive(Component)]
struct Menu;
fn setup(mut commands: Commands, textures: Res<TextureAssets>) {
commands.spawn((Camera2dBundle::default(), Menu));
commands
.spawn((
NodeBundle {
style: Style {
width: Val::Percent(100.0),
height: Val::Percent(100.0),
flex_direction: FlexDirection::Column,
align_items: AlignItems::Center,
justify_content: JustifyContent::Center,
..default()
},
..default()
},
Menu,
))
.with_children(|children| {
let button_colours = ButtonColours::default();
children
.spawn((
ButtonBundle {
style: Style {
width: Val::Px(140.0),
height: Val::Px(90.0),
justify_content: JustifyContent::Center,
align_items: AlignItems::Center,
..default()
},
background_color: button_colours.normal.into(),
..default()
},
button_colours,
ChangeState(GameState::Playing),
))
.with_children(|parent| {
parent.spawn(TextBundle::from_section(
"Play",
TextStyle {
font_size: 40.0,
color: Color::srgb(205.0 / 255.0, 214.0 / 255.0, 244.0 / 255.0),
..default()
},
));
});
});
commands
.spawn((
NodeBundle {
style: Style {
flex_direction: FlexDirection::Row,
align_items: AlignItems::Center,
justify_content: JustifyContent::SpaceAround,
bottom: Val::Px(5.),
width: Val::Percent(100.),
position_type: PositionType::Absolute,
..default()
},
..default()
},
Menu,
))
.with_children(|children| {
children
.spawn((
ButtonBundle {
style: Style {
width: Val::Px(170.0),
height: Val::Px(50.0),
justify_content: JustifyContent::SpaceAround,
align_items: AlignItems::Center,
padding: UiRect::all(Val::Px(5.)),
..Default::default()
},
background_color: Color::NONE.into(),
..Default::default()
},
ButtonColours {
normal: Color::NONE,
..default()
},
OpenLink("https://bevyengine.org"),
))
.with_children(|parent| {
parent.spawn(TextBundle::from_section(
"Made with Bevy",
TextStyle {
font_size: 15.0,
color: Color::srgb(205.0 / 255.0, 214.0 / 255.0, 244.0 / 255.0),
..default()
},
));
parent.spawn(ImageBundle {
image: textures.bevy.clone().into(),
style: Style {
width: Val::Px(32.),
..default()
},
..default()
});
});
children
.spawn((
ButtonBundle {
style: Style {
width: Val::Px(170.0),
height: Val::Px(50.0),
justify_content: JustifyContent::SpaceAround,
align_items: AlignItems::Center,
padding: UiRect::all(Val::Px(5.)),
..default()
},
background_color: Color::NONE.into(),
..Default::default()
},
ButtonColours {
normal: Color::NONE,
..default()
},
OpenLink("https://git.ragarock.moe/silvana/yuno"),
))
.with_children(|parent| {
parent.spawn(TextBundle::from_section(
"repository",
TextStyle {
font_size: 15.0,
color: Color::srgb(205.0 / 255.0, 214.0 / 255.0, 244.0 / 255.0),
..default()
},
));
parent.spawn(ImageBundle {
image: textures.forgejo.clone().into(),
style: Style {
width: Val::Px(32.),
..default()
},
..default()
});
});
});
}
#[derive(Component)]
struct ChangeState(GameState);
#[derive(Component)]
struct OpenLink(&'static str);
fn click_button(
mut next_state: ResMut<NextState<GameState>>,
mut interaction_query: Query<
(
&Interaction,
&mut BackgroundColor,
&ButtonColours,
Option<&ChangeState>,
Option<&OpenLink>,
),
(Changed<Interaction>, With<Button>),
>,
) {
for (interaction, mut colour, button_colours, change_state, open_link) in &mut interaction_query
{
match *interaction {
Interaction::Pressed => {
if let Some(state) = change_state {
next_state.set(state.0.clone());
} else if let Some(link) = open_link {
if let Err(error) = webbrowser::open(link.0) {
warn!("failed to open link {error:?}");
}
}
}
Interaction::Hovered => {
*colour = button_colours.hovered.into();
}
Interaction::None => {
*colour = button_colours.normal.into();
}
}
}
}
fn cleanup(mut commands: Commands, menu: Query<Entity, With<Menu>>) {
for entity in menu.iter() {
commands.entity(entity).despawn_recursive();
}
}