Compare commits
3 commits
main
...
feature/di
Author | SHA1 | Date | |
---|---|---|---|
cacda7fc2b | |||
d90980ddca | |||
4511c8f953 |
19 changed files with 778 additions and 3 deletions
1
.gitattributes
vendored
1
.gitattributes
vendored
|
@ -1 +1,2 @@
|
||||||
*.ico filter=lfs diff=lfs merge=lfs -text
|
*.ico filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.png filter=lfs diff=lfs merge=lfs -text
|
||||||
|
|
|
@ -10,6 +10,8 @@ license = "MIT OR Apache-2.0"
|
||||||
repository = "https://forgejo.fireturlte.net/lazy-supplements"
|
repository = "https://forgejo.fireturlte.net/lazy-supplements"
|
||||||
|
|
||||||
[workspace.dependencies]
|
[workspace.dependencies]
|
||||||
|
bevy = "0.16.1"
|
||||||
|
clap = { version = "4.5.38", features = ["derive"] }
|
||||||
dioxus = { version = "0.6.0", features = [] }
|
dioxus = { version = "0.6.0", features = [] }
|
||||||
lazy-supplements-core.path = "lazy-supplements-core"
|
lazy-supplements-core.path = "lazy-supplements-core"
|
||||||
libp2p = { version = "0.55.0", features = ["macros", "mdns", "noise", "ping", "tcp", "tokio", "yamux" ] }
|
libp2p = { version = "0.55.0", features = ["macros", "mdns", "noise", "ping", "tcp", "tokio", "yamux" ] }
|
||||||
|
|
|
@ -7,4 +7,5 @@ license.workspace = true
|
||||||
repository.workspace = true
|
repository.workspace = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
bevy.workspace = true
|
||||||
dioxus.workspace = true
|
dioxus.workspace = true
|
BIN
examples/core/assets/playful/textures/Game Icons/exitRight.png
(Stored with Git LFS)
Normal file
BIN
examples/core/assets/playful/textures/Game Icons/exitRight.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
examples/core/assets/playful/textures/Game Icons/right.png
(Stored with Git LFS)
Normal file
BIN
examples/core/assets/playful/textures/Game Icons/right.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
examples/core/assets/playful/textures/Game Icons/wrench.png
(Stored with Git LFS)
Normal file
BIN
examples/core/assets/playful/textures/Game Icons/wrench.png
(Stored with Git LFS)
Normal file
Binary file not shown.
|
@ -1 +1,2 @@
|
||||||
pub mod plain;
|
pub mod plain;
|
||||||
|
pub mod playful;
|
56
examples/core/src/ui/playful/mod.rs
Normal file
56
examples/core/src/ui/playful/mod.rs
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
mod plugins;
|
||||||
|
pub mod themes;
|
||||||
|
|
||||||
|
use bevy::prelude::*;
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Default, Eq, PartialEq, Debug, Hash, States)]
|
||||||
|
enum AppState {
|
||||||
|
#[default]
|
||||||
|
Loading,
|
||||||
|
MainView,
|
||||||
|
Menu,
|
||||||
|
List,
|
||||||
|
Graph
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Resource, Debug, Component, PartialEq, Eq, Clone, Copy)]
|
||||||
|
enum DisplayQuality {
|
||||||
|
Low,
|
||||||
|
Medium,
|
||||||
|
High,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Resource, Debug, Component, PartialEq, Eq, Clone, Copy)]
|
||||||
|
struct Volume(u32);
|
||||||
|
|
||||||
|
#[derive(Resource, Debug, Component, PartialEq, Eq, Clone, Copy)]
|
||||||
|
enum ViewerMode {
|
||||||
|
PokerTip2D,
|
||||||
|
PokerTip3D,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run_playful_app() {
|
||||||
|
App::new()
|
||||||
|
.add_plugins(DefaultPlugins)
|
||||||
|
.insert_resource(DisplayQuality::Medium)
|
||||||
|
.insert_resource(Volume(7))
|
||||||
|
.insert_resource(ViewerMode::PokerTip2D)
|
||||||
|
.init_state::<AppState>()
|
||||||
|
.add_systems(Startup, setup)
|
||||||
|
.add_plugins((plugins::loading::loading_plugin, plugins::main_menu::menu_plugin, plugins::main_view::main_view_plugin))
|
||||||
|
.run();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fn setup(mut commands: Commands) {
|
||||||
|
commands.spawn(Camera2d);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Generic system that takes a component as a parameter, and will despawn all entities with that component
|
||||||
|
fn despawn_screen<T: Component>(to_despawn: Query<Entity, With<T>>, mut commands: Commands) {
|
||||||
|
for entity in &to_despawn {
|
||||||
|
commands.entity(entity).despawn();
|
||||||
|
}
|
||||||
|
}
|
59
examples/core/src/ui/playful/plugins/loading.rs
Normal file
59
examples/core/src/ui/playful/plugins/loading.rs
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
use bevy::prelude::*;
|
||||||
|
|
||||||
|
use crate::ui::playful::{despawn_screen, AppState};
|
||||||
|
|
||||||
|
// This plugin will display a splash screen with Bevy logo for 1 second before switching to the menu
|
||||||
|
pub fn loading_plugin(app: &mut App) {
|
||||||
|
// As this plugin is managing the splash screen, it will focus on the state `GameState::Splash`
|
||||||
|
app
|
||||||
|
// When entering the state, spawn everything needed for this screen
|
||||||
|
.add_systems(OnEnter(AppState::Loading), loading_setup)
|
||||||
|
// While in this state, run the `countdown` system
|
||||||
|
.add_systems(Update, countdown.run_if(in_state(AppState::Loading)))
|
||||||
|
// When exiting the state, despawn everything that was spawned for this screen
|
||||||
|
.add_systems(OnExit(AppState::Loading), despawn_screen::<OnLoadingScreen>);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tag component used to tag entities added on the splash screen
|
||||||
|
#[derive(Component)]
|
||||||
|
struct OnLoadingScreen;
|
||||||
|
|
||||||
|
// Newtype to use a `Timer` for this screen as a resource
|
||||||
|
#[derive(Resource, Deref, DerefMut)]
|
||||||
|
struct LoadingTimer(Timer);
|
||||||
|
|
||||||
|
fn loading_setup(mut commands: Commands, asset_server: Res<AssetServer>) {
|
||||||
|
//let icon = asset_server.load("textures/Game Icons/wrench.png");
|
||||||
|
// Display the logo
|
||||||
|
commands.spawn((
|
||||||
|
Node {
|
||||||
|
align_items: AlignItems::Center,
|
||||||
|
justify_content: JustifyContent::Center,
|
||||||
|
width: Val::Percent(100.0),
|
||||||
|
height: Val::Percent(100.0),
|
||||||
|
..default()
|
||||||
|
},
|
||||||
|
OnLoadingScreen,
|
||||||
|
children![(
|
||||||
|
//ImageNode::new(icon),
|
||||||
|
Node {
|
||||||
|
// This will set the logo to be 200px wide, and auto adjust its height
|
||||||
|
width: Val::Px(200.0),
|
||||||
|
..default()
|
||||||
|
},
|
||||||
|
)],
|
||||||
|
));
|
||||||
|
// Insert the timer as a resource
|
||||||
|
commands.insert_resource(LoadingTimer(Timer::from_seconds(1.0, TimerMode::Once)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tick the timer, and change state when finished
|
||||||
|
fn countdown(
|
||||||
|
mut game_state: ResMut<NextState<AppState>>,
|
||||||
|
time: Res<Time>,
|
||||||
|
mut timer: ResMut<LoadingTimer>,
|
||||||
|
) {
|
||||||
|
if timer.tick(time.delta()).finished() {
|
||||||
|
game_state.set(AppState::MainView);
|
||||||
|
}
|
||||||
|
}
|
475
examples/core/src/ui/playful/plugins/main_menu.rs
Normal file
475
examples/core/src/ui/playful/plugins/main_menu.rs
Normal file
|
@ -0,0 +1,475 @@
|
||||||
|
use bevy::{
|
||||||
|
app::AppExit,
|
||||||
|
color::palettes::css::CRIMSON,
|
||||||
|
ecs::spawn::{SpawnIter, SpawnWith},
|
||||||
|
prelude::*,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::ui::playful::{
|
||||||
|
despawn_screen,
|
||||||
|
themes::dark::{self, NORMAL_BUTTON},
|
||||||
|
DisplayQuality,
|
||||||
|
AppState,
|
||||||
|
Volume,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Default, Eq, PartialEq, Debug, Hash, States)]
|
||||||
|
enum MenuState {
|
||||||
|
Main,
|
||||||
|
Settings,
|
||||||
|
SettingsDisplay,
|
||||||
|
SettingsVolume,
|
||||||
|
#[default]
|
||||||
|
Disabled,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn menu_plugin(app: &mut App) {
|
||||||
|
app
|
||||||
|
.init_state::<MenuState>()
|
||||||
|
.add_systems(OnEnter(AppState::Menu), menu_setup)
|
||||||
|
.add_systems(OnEnter(MenuState::Main), main_menu_setup)
|
||||||
|
.add_systems(OnExit(MenuState::Main), despawn_screen::<OnMainMenuScreen>)
|
||||||
|
.add_systems(OnEnter(MenuState::Settings), settings_menu_setup)
|
||||||
|
.add_systems(
|
||||||
|
OnExit(MenuState::Settings),
|
||||||
|
despawn_screen::<OnSettingsMenuScreen>
|
||||||
|
)
|
||||||
|
.add_systems(OnEnter(MenuState::SettingsDisplay), display_settings_menu_setup)
|
||||||
|
.add_systems(
|
||||||
|
Update,
|
||||||
|
(setting_button::<DisplayQuality>.run_if(in_state(MenuState::SettingsDisplay)))
|
||||||
|
)
|
||||||
|
.add_systems(
|
||||||
|
OnExit(MenuState::SettingsDisplay),
|
||||||
|
despawn_screen::<OnDisplaySettingsMenuScreen>
|
||||||
|
)
|
||||||
|
.add_systems(OnEnter(MenuState::SettingsVolume), sound_settings_menu_setup)
|
||||||
|
.add_systems(
|
||||||
|
Update,
|
||||||
|
(setting_button::<Volume>.run_if(in_state(MenuState::SettingsVolume)))
|
||||||
|
)
|
||||||
|
.add_systems(
|
||||||
|
OnExit(MenuState::SettingsVolume),
|
||||||
|
despawn_screen::<OnSoundSettingsMenuScreen>
|
||||||
|
)
|
||||||
|
.add_systems(
|
||||||
|
Update,
|
||||||
|
(menu_action, button_system).run_if(in_state(AppState::Menu))
|
||||||
|
)
|
||||||
|
|
||||||
|
;
|
||||||
|
}
|
||||||
|
#[derive(Component)]
|
||||||
|
struct OnMainMenuScreen;
|
||||||
|
|
||||||
|
#[derive(Component)]
|
||||||
|
struct OnSettingsMenuScreen;
|
||||||
|
|
||||||
|
#[derive(Component)]
|
||||||
|
struct OnDisplaySettingsMenuScreen;
|
||||||
|
|
||||||
|
#[derive(Component)]
|
||||||
|
struct OnSoundSettingsMenuScreen;
|
||||||
|
|
||||||
|
#[derive(Component)]
|
||||||
|
struct SelectedOption;
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Component)]
|
||||||
|
enum MenuButtonAction {
|
||||||
|
BackToMainView,
|
||||||
|
BackToMainMenu,
|
||||||
|
BackToSettings,
|
||||||
|
Settings,
|
||||||
|
SettingsDisplay,
|
||||||
|
SettingsSound,
|
||||||
|
Quit,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn button_system(
|
||||||
|
mut interaction_query: Query<(&Interaction, &mut BackgroundColor, Option<&SelectedOption>),(Changed<Interaction>, With<Button>)>
|
||||||
|
) {
|
||||||
|
for (interaction, mut background_color, selected) in &mut interaction_query {
|
||||||
|
*background_color = match (*interaction, selected) {
|
||||||
|
(Interaction::Pressed, _) | (_, Some(_)) => dark::PRESSED_BUTTON.into(),
|
||||||
|
(Interaction::Hovered, None) => dark::HOVERED_BUTTON.into(),
|
||||||
|
(Interaction::None, None) => dark::NORMAL_BUTTON.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn setting_button<T: Resource + Component + PartialEq + Copy> (
|
||||||
|
interaction_query: Query<(&Interaction, &T, Entity), (Changed<Interaction>, With<Button>)>,
|
||||||
|
selected_query: Single<(Entity, &mut BackgroundColor), With<SelectedOption>>,
|
||||||
|
mut commands: Commands,
|
||||||
|
mut setting: ResMut<T>
|
||||||
|
) {
|
||||||
|
let (previous_button, mut previous_button_color) = selected_query.into_inner();
|
||||||
|
for (interaction, button_setting, entity) in &interaction_query {
|
||||||
|
if *interaction == Interaction::Pressed && *setting != *button_setting {
|
||||||
|
*previous_button_color = NORMAL_BUTTON.into();
|
||||||
|
commands.entity(previous_button).remove::<SelectedOption>();
|
||||||
|
commands.entity(entity).insert(SelectedOption);
|
||||||
|
*setting = *button_setting
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn menu_setup(mut menu_state: ResMut<NextState<MenuState>>) {
|
||||||
|
menu_state.set(MenuState::Main);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main_menu_setup(mut commands: Commands, asset_server: Res<AssetServer>) {
|
||||||
|
let button_node = Node {
|
||||||
|
width: Val::Px(300.0),
|
||||||
|
height: Val::Px(65.0),
|
||||||
|
margin: UiRect::all(Val::Px(20.0)),
|
||||||
|
justify_content: JustifyContent::Center,
|
||||||
|
align_items: AlignItems::Center,
|
||||||
|
..default()
|
||||||
|
};
|
||||||
|
let button_icon_node = Node {
|
||||||
|
width: Val::Px(30.0),
|
||||||
|
position_type: PositionType::Absolute,
|
||||||
|
left: Val::Px(10.0),
|
||||||
|
..default()
|
||||||
|
};
|
||||||
|
let button_text_font = TextFont {
|
||||||
|
font_size: 33.0,
|
||||||
|
..default()
|
||||||
|
};
|
||||||
|
//let right_icon = asset_server.load("playful/textures/Game Icons/right.png");
|
||||||
|
//let wrench_icon = asset_server.load("playful/textures/Game Icons/wrench.png");
|
||||||
|
//let exit_icon = asset_server.load("playful/textures/Game Icons/exitRight.png");
|
||||||
|
|
||||||
|
|
||||||
|
commands.spawn((
|
||||||
|
Node {
|
||||||
|
width: Val::Percent(100.0),
|
||||||
|
height: Val::Percent(100.0),
|
||||||
|
align_items: AlignItems::Center,
|
||||||
|
justify_content: JustifyContent::Center,
|
||||||
|
..default()
|
||||||
|
},
|
||||||
|
OnMainMenuScreen,
|
||||||
|
children![(
|
||||||
|
Node {
|
||||||
|
flex_direction: FlexDirection::Column,
|
||||||
|
align_items: AlignItems::Center,
|
||||||
|
..default()
|
||||||
|
},
|
||||||
|
BackgroundColor(dark::BACKGROUND_COLOR.into()),
|
||||||
|
children![
|
||||||
|
(
|
||||||
|
Text::new("Progress Pile"),
|
||||||
|
TextFont {
|
||||||
|
font_size: 67.0,
|
||||||
|
..default()
|
||||||
|
},
|
||||||
|
TextColor(dark::TEXT_COLOR),
|
||||||
|
Node {
|
||||||
|
margin: UiRect::all(Val::Px(50.0)),
|
||||||
|
..default()
|
||||||
|
},
|
||||||
|
),
|
||||||
|
(
|
||||||
|
Button,
|
||||||
|
button_node.clone(),
|
||||||
|
BackgroundColor(dark::NORMAL_BUTTON),
|
||||||
|
MenuButtonAction::BackToMainView,
|
||||||
|
children![
|
||||||
|
// (ImageNode::new(right_icon), button_icon_node.clone()),
|
||||||
|
(
|
||||||
|
Text::new("Back to main window"),
|
||||||
|
button_text_font.clone(),
|
||||||
|
TextColor(dark::TEXT_COLOR),
|
||||||
|
)
|
||||||
|
]
|
||||||
|
),
|
||||||
|
(
|
||||||
|
Button,
|
||||||
|
button_node.clone(),
|
||||||
|
BackgroundColor(dark::NORMAL_BUTTON),
|
||||||
|
MenuButtonAction::Settings,
|
||||||
|
children![
|
||||||
|
// (ImageNode::new(wrench_icon), button_icon_node.clone()),
|
||||||
|
(
|
||||||
|
Text::new("Settings"),
|
||||||
|
button_text_font.clone(),
|
||||||
|
TextColor(dark::TEXT_COLOR),
|
||||||
|
)
|
||||||
|
]
|
||||||
|
),
|
||||||
|
(
|
||||||
|
Button,
|
||||||
|
button_node.clone(),
|
||||||
|
BackgroundColor(dark::NORMAL_BUTTON),
|
||||||
|
MenuButtonAction::Quit,
|
||||||
|
children![
|
||||||
|
// (ImageNode::new(exit_icon), button_icon_node.clone()),
|
||||||
|
(
|
||||||
|
Text::new("Quit"),
|
||||||
|
button_text_font.clone(),
|
||||||
|
TextColor(dark::TEXT_COLOR),
|
||||||
|
)
|
||||||
|
]
|
||||||
|
),
|
||||||
|
]
|
||||||
|
)]
|
||||||
|
));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fn settings_menu_setup(mut commands: Commands) {
|
||||||
|
let button_node = Node {
|
||||||
|
width: Val::Px(200.0),
|
||||||
|
height: Val::Px(65.0),
|
||||||
|
margin: UiRect::all(Val::Px(20.0)),
|
||||||
|
justify_content: JustifyContent::Center,
|
||||||
|
align_items: AlignItems::Center,
|
||||||
|
..default()
|
||||||
|
};
|
||||||
|
|
||||||
|
let button_text_style = (
|
||||||
|
TextFont {
|
||||||
|
font_size: 33.0,
|
||||||
|
..default()
|
||||||
|
},
|
||||||
|
TextColor(dark::TEXT_COLOR),
|
||||||
|
);
|
||||||
|
|
||||||
|
commands.spawn((
|
||||||
|
Node {
|
||||||
|
width: Val::Percent(100.0),
|
||||||
|
height: Val::Percent(100.0),
|
||||||
|
align_items: AlignItems::Center,
|
||||||
|
justify_content: JustifyContent::Center,
|
||||||
|
..default()
|
||||||
|
},
|
||||||
|
OnSettingsMenuScreen,
|
||||||
|
children![(
|
||||||
|
Node {
|
||||||
|
flex_direction: FlexDirection::Column,
|
||||||
|
align_items: AlignItems::Center,
|
||||||
|
..default()
|
||||||
|
},
|
||||||
|
BackgroundColor(CRIMSON.into()),
|
||||||
|
Children::spawn(SpawnIter(
|
||||||
|
[
|
||||||
|
(MenuButtonAction::SettingsDisplay, "Display"),
|
||||||
|
(MenuButtonAction::SettingsSound, "Sound"),
|
||||||
|
(MenuButtonAction::BackToMainMenu, "Back"),
|
||||||
|
]
|
||||||
|
.into_iter()
|
||||||
|
.map(move |(action, text)| {
|
||||||
|
(
|
||||||
|
Button,
|
||||||
|
button_node.clone(),
|
||||||
|
BackgroundColor(NORMAL_BUTTON),
|
||||||
|
action,
|
||||||
|
children![(Text::new(text), button_text_style.clone())],
|
||||||
|
)
|
||||||
|
})
|
||||||
|
))
|
||||||
|
)],
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn display_settings_menu_setup(mut commands: Commands, display_quality: Res<DisplayQuality>) {
|
||||||
|
fn button_node() -> Node {
|
||||||
|
Node {
|
||||||
|
width: Val::Px(200.0),
|
||||||
|
height: Val::Px(65.0),
|
||||||
|
margin: UiRect::all(Val::Px(20.0)),
|
||||||
|
justify_content: JustifyContent::Center,
|
||||||
|
align_items: AlignItems::Center,
|
||||||
|
..default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn button_text_style() -> impl Bundle {
|
||||||
|
(
|
||||||
|
TextFont {
|
||||||
|
font_size: 33.0,
|
||||||
|
..default()
|
||||||
|
},
|
||||||
|
TextColor(dark::TEXT_COLOR),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
let display_quality = *display_quality;
|
||||||
|
commands.spawn((
|
||||||
|
Node {
|
||||||
|
width: Val::Percent(100.0),
|
||||||
|
height: Val::Percent(100.0),
|
||||||
|
align_items: AlignItems::Center,
|
||||||
|
justify_content: JustifyContent::Center,
|
||||||
|
..default()
|
||||||
|
},
|
||||||
|
OnDisplaySettingsMenuScreen,
|
||||||
|
children![(
|
||||||
|
Node {
|
||||||
|
flex_direction: FlexDirection::Column,
|
||||||
|
align_items: AlignItems::Center,
|
||||||
|
..default()
|
||||||
|
},
|
||||||
|
BackgroundColor(CRIMSON.into()),
|
||||||
|
children![
|
||||||
|
// Create a new `Node`, this time not setting its `flex_direction`. It will
|
||||||
|
// use the default value, `FlexDirection::Row`, from left to right.
|
||||||
|
(
|
||||||
|
Node {
|
||||||
|
align_items: AlignItems::Center,
|
||||||
|
..default()
|
||||||
|
},
|
||||||
|
BackgroundColor(CRIMSON.into()),
|
||||||
|
Children::spawn((
|
||||||
|
// Display a label for the current setting
|
||||||
|
Spawn((Text::new("Display Quality"), button_text_style())),
|
||||||
|
SpawnWith(move |parent: &mut ChildSpawner| {
|
||||||
|
for quality_setting in [
|
||||||
|
DisplayQuality::Low,
|
||||||
|
DisplayQuality::Medium,
|
||||||
|
DisplayQuality::High,
|
||||||
|
] {
|
||||||
|
let mut entity = parent.spawn((
|
||||||
|
Button,
|
||||||
|
Node {
|
||||||
|
width: Val::Px(150.0),
|
||||||
|
height: Val::Px(65.0),
|
||||||
|
..button_node()
|
||||||
|
},
|
||||||
|
BackgroundColor(NORMAL_BUTTON),
|
||||||
|
quality_setting,
|
||||||
|
children![(
|
||||||
|
Text::new(format!("{quality_setting:?}")),
|
||||||
|
button_text_style(),
|
||||||
|
)],
|
||||||
|
));
|
||||||
|
if display_quality == quality_setting {
|
||||||
|
entity.insert(SelectedOption);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
))
|
||||||
|
),
|
||||||
|
// Display the back button to return to the settings screen
|
||||||
|
(
|
||||||
|
Button,
|
||||||
|
button_node(),
|
||||||
|
BackgroundColor(NORMAL_BUTTON),
|
||||||
|
MenuButtonAction::BackToSettings,
|
||||||
|
children![(Text::new("Back"), button_text_style())]
|
||||||
|
)
|
||||||
|
]
|
||||||
|
)],
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sound_settings_menu_setup(mut commands: Commands, volume: Res<Volume>) {
|
||||||
|
let button_node = Node {
|
||||||
|
width: Val::Px(200.0),
|
||||||
|
height: Val::Px(65.0),
|
||||||
|
margin: UiRect::all(Val::Px(20.0)),
|
||||||
|
justify_content: JustifyContent::Center,
|
||||||
|
align_items: AlignItems::Center,
|
||||||
|
..default()
|
||||||
|
};
|
||||||
|
let button_text_style = (
|
||||||
|
TextFont {
|
||||||
|
font_size: 33.0,
|
||||||
|
..default()
|
||||||
|
},
|
||||||
|
TextColor(dark::TEXT_COLOR),
|
||||||
|
);
|
||||||
|
|
||||||
|
let volume = *volume;
|
||||||
|
let button_node_clone = button_node.clone();
|
||||||
|
commands.spawn((
|
||||||
|
Node {
|
||||||
|
width: Val::Percent(100.0),
|
||||||
|
height: Val::Percent(100.0),
|
||||||
|
align_items: AlignItems::Center,
|
||||||
|
justify_content: JustifyContent::Center,
|
||||||
|
..default()
|
||||||
|
},
|
||||||
|
OnSoundSettingsMenuScreen,
|
||||||
|
children![(
|
||||||
|
Node {
|
||||||
|
flex_direction: FlexDirection::Column,
|
||||||
|
align_items: AlignItems::Center,
|
||||||
|
..default()
|
||||||
|
},
|
||||||
|
BackgroundColor(CRIMSON.into()),
|
||||||
|
children![
|
||||||
|
(
|
||||||
|
Node {
|
||||||
|
align_items: AlignItems::Center,
|
||||||
|
..default()
|
||||||
|
},
|
||||||
|
BackgroundColor(CRIMSON.into()),
|
||||||
|
Children::spawn((
|
||||||
|
Spawn((Text::new("Volume"), button_text_style.clone())),
|
||||||
|
SpawnWith(move |parent: &mut ChildSpawner| {
|
||||||
|
for volume_setting in [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] {
|
||||||
|
let mut entity = parent.spawn((
|
||||||
|
Button,
|
||||||
|
Node {
|
||||||
|
width: Val::Px(30.0),
|
||||||
|
height: Val::Px(65.0),
|
||||||
|
..button_node_clone.clone()
|
||||||
|
},
|
||||||
|
BackgroundColor(NORMAL_BUTTON),
|
||||||
|
Volume(volume_setting),
|
||||||
|
));
|
||||||
|
if volume == Volume(volume_setting) {
|
||||||
|
entity.insert(SelectedOption);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
))
|
||||||
|
),
|
||||||
|
(
|
||||||
|
Button,
|
||||||
|
button_node,
|
||||||
|
BackgroundColor(NORMAL_BUTTON),
|
||||||
|
MenuButtonAction::BackToSettings,
|
||||||
|
children![(Text::new("Back"), button_text_style)]
|
||||||
|
)
|
||||||
|
]
|
||||||
|
)],
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn menu_action(
|
||||||
|
interaction_query: Query<
|
||||||
|
(&Interaction, &MenuButtonAction),
|
||||||
|
(Changed<Interaction>, With<Button>),
|
||||||
|
>,
|
||||||
|
mut app_exit_events: EventWriter<AppExit>,
|
||||||
|
mut menu_state: ResMut<NextState<MenuState>>,
|
||||||
|
mut game_state: ResMut<NextState<AppState>>,
|
||||||
|
) {
|
||||||
|
for (interaction, menu_button_action) in &interaction_query {
|
||||||
|
if *interaction == Interaction::Pressed {
|
||||||
|
match menu_button_action {
|
||||||
|
MenuButtonAction::Quit => {
|
||||||
|
app_exit_events.write(AppExit::Success);
|
||||||
|
}
|
||||||
|
MenuButtonAction::BackToMainView => {
|
||||||
|
game_state.set(AppState::MainView);
|
||||||
|
menu_state.set(MenuState::Disabled);
|
||||||
|
}
|
||||||
|
MenuButtonAction::Settings => menu_state.set(MenuState::Settings),
|
||||||
|
MenuButtonAction::SettingsDisplay => {
|
||||||
|
menu_state.set(MenuState::SettingsDisplay);
|
||||||
|
}
|
||||||
|
MenuButtonAction::SettingsSound => {
|
||||||
|
menu_state.set(MenuState::SettingsVolume);
|
||||||
|
}
|
||||||
|
MenuButtonAction::BackToMainMenu => menu_state.set(MenuState::Main),
|
||||||
|
MenuButtonAction::BackToSettings => {
|
||||||
|
menu_state.set(MenuState::Settings);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
113
examples/core/src/ui/playful/plugins/main_view.rs
Normal file
113
examples/core/src/ui/playful/plugins/main_view.rs
Normal file
|
@ -0,0 +1,113 @@
|
||||||
|
use bevy::{
|
||||||
|
app::AppExit,
|
||||||
|
color::palettes::css::CRIMSON,
|
||||||
|
ecs::spawn::{SpawnIter, SpawnWith},
|
||||||
|
prelude::*,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::ui::playful::{
|
||||||
|
despawn_screen,
|
||||||
|
themes::dark::{self, NORMAL_BUTTON},
|
||||||
|
DisplayQuality,
|
||||||
|
AppState,
|
||||||
|
Volume,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn main_view_plugin(app: &mut App) {
|
||||||
|
app
|
||||||
|
.add_systems(OnEnter(AppState::MainView), main_view_setup)
|
||||||
|
.add_systems(OnExit(AppState::MainView), despawn_screen::<OnMainViewScreen>)
|
||||||
|
.add_systems(
|
||||||
|
Update,
|
||||||
|
(menu_action, button_system).run_if(in_state(AppState::MainView))
|
||||||
|
)
|
||||||
|
|
||||||
|
;
|
||||||
|
}
|
||||||
|
#[derive(Component)]
|
||||||
|
struct OnMainViewScreen;
|
||||||
|
|
||||||
|
#[derive(Component)]
|
||||||
|
struct SelectedOption;
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Component)]
|
||||||
|
enum MainViewButtonAction {
|
||||||
|
OpenMainMenu,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn button_system(
|
||||||
|
mut interaction_query: Query<(&Interaction, &mut BackgroundColor, Option<&SelectedOption>),(Changed<Interaction>, With<Button>)>
|
||||||
|
) {
|
||||||
|
for (interaction, mut background_color, selected) in &mut interaction_query {
|
||||||
|
*background_color = match (*interaction, selected) {
|
||||||
|
(Interaction::Pressed, _) | (_, Some(_)) => dark::PRESSED_BUTTON.into(),
|
||||||
|
(Interaction::Hovered, None) => dark::HOVERED_BUTTON.into(),
|
||||||
|
(Interaction::None, None) => dark::NORMAL_BUTTON.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main_view_setup(mut commands: Commands, asset_server: Res<AssetServer>) {
|
||||||
|
let header_node = Node {
|
||||||
|
width: Val::Percent(100.0),
|
||||||
|
height: Val::Px(20.0),
|
||||||
|
justify_content: JustifyContent::SpaceBetween,
|
||||||
|
align_items: AlignItems::Center,
|
||||||
|
..default()
|
||||||
|
};
|
||||||
|
let body_node = Node{
|
||||||
|
width: Val::Percent(100.0),
|
||||||
|
height: Val::Auto,
|
||||||
|
..default()
|
||||||
|
};
|
||||||
|
// let wrench_icon = asset_server.load("textures/Game Icons/wrench.png");
|
||||||
|
|
||||||
|
commands.spawn((
|
||||||
|
Node {
|
||||||
|
width: Val::Percent(100.0),
|
||||||
|
height: Val::Percent(100.0),
|
||||||
|
justify_content: JustifyContent::Center,
|
||||||
|
align_items: AlignItems::Center,
|
||||||
|
..default()
|
||||||
|
},
|
||||||
|
OnMainViewScreen,
|
||||||
|
children![(
|
||||||
|
header_node,
|
||||||
|
children![(
|
||||||
|
Button,
|
||||||
|
Node{
|
||||||
|
width: Val::Px(30.0),
|
||||||
|
..default()
|
||||||
|
},
|
||||||
|
MainViewButtonAction::OpenMainMenu,
|
||||||
|
children![(
|
||||||
|
Text::new("Settings"),
|
||||||
|
Node::default()
|
||||||
|
)
|
||||||
|
]
|
||||||
|
|
||||||
|
)]
|
||||||
|
)]
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn menu_action(
|
||||||
|
interaction_query: Query<
|
||||||
|
(&Interaction, &MainViewButtonAction),
|
||||||
|
(Changed<Interaction>, With<Button>),
|
||||||
|
>,
|
||||||
|
mut app_exit_events: EventWriter<AppExit>,
|
||||||
|
mut game_state: ResMut<NextState<AppState>>,
|
||||||
|
) {
|
||||||
|
for (interaction, menu_button_action) in &interaction_query {
|
||||||
|
if *interaction == Interaction::Pressed {
|
||||||
|
match menu_button_action {
|
||||||
|
MainViewButtonAction::OpenMainMenu => {
|
||||||
|
game_state.set(AppState::Menu);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
3
examples/core/src/ui/playful/plugins/mod.rs
Normal file
3
examples/core/src/ui/playful/plugins/mod.rs
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
pub mod loading;
|
||||||
|
pub mod main_menu;
|
||||||
|
pub mod main_view;
|
7
examples/core/src/ui/playful/themes/dark.rs
Normal file
7
examples/core/src/ui/playful/themes/dark.rs
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
use bevy::prelude::*;
|
||||||
|
|
||||||
|
pub const TEXT_COLOR: Color = Color::srgb(0.9, 0.9, 0.9);
|
||||||
|
pub const BACKGROUND_COLOR: Color = Color::srgb(0.1, 0.1, 0.1);
|
||||||
|
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.5,0.5, 0.5);
|
4
examples/core/src/ui/playful/themes/light.rs
Normal file
4
examples/core/src/ui/playful/themes/light.rs
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
use bevy::prelude::*;
|
||||||
|
|
||||||
|
const TEXT_COLOR: Color = Color::srgb(0.1, 0.1, 0.1);
|
||||||
|
const BACKGROUND_COLOR: Color = Color::srgb(0.9, 0.9, 0.9);
|
12
examples/core/src/ui/playful/themes/mod.rs
Normal file
12
examples/core/src/ui/playful/themes/mod.rs
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
use bevy::prelude::*;
|
||||||
|
|
||||||
|
pub mod dark;
|
||||||
|
pub mod light;
|
||||||
|
|
||||||
|
#[derive(Resource, Debug, Component, Default, PartialEq, Eq, Clone, Copy)]
|
||||||
|
pub enum UiTheme {
|
||||||
|
Light,
|
||||||
|
Dark,
|
||||||
|
#[default]
|
||||||
|
Default,
|
||||||
|
}
|
|
@ -6,6 +6,7 @@ edition = "2021"
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
clap.workspace = true
|
||||||
dioxus.workspace = true
|
dioxus.workspace = true
|
||||||
lazy-supplements-examples-core.path = "../core"
|
lazy-supplements-examples-core.path = "../core"
|
||||||
|
|
||||||
|
|
16
examples/desktop/src/cli.rs
Normal file
16
examples/desktop/src/cli.rs
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
use clap::{Args, Parser};
|
||||||
|
|
||||||
|
#[derive(Debug, Parser)]
|
||||||
|
pub struct Cli {
|
||||||
|
#[command(flatten)]
|
||||||
|
pub gui_mode: GuiModeArgs
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Args, Debug)]
|
||||||
|
#[group(required=true, multiple = false)]
|
||||||
|
pub struct GuiModeArgs {
|
||||||
|
#[arg(long)]
|
||||||
|
pub plain: bool,
|
||||||
|
#[arg(long)]
|
||||||
|
pub playful: bool,
|
||||||
|
}
|
|
@ -1,3 +1,18 @@
|
||||||
|
use crate::cli::Cli;
|
||||||
|
use clap::Parser;
|
||||||
|
use lazy_supplements_examples_core::ui::playful::run_playful_app;
|
||||||
|
|
||||||
|
mod cli;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
dioxus::launch(lazy_supplements_examples_core::ui::plain::App);
|
match Cli::try_parse() {
|
||||||
|
Ok(x) => {
|
||||||
|
if x.gui_mode.plain {
|
||||||
|
dioxus::launch(lazy_supplements_examples_core::ui::plain::App);
|
||||||
|
} else if x.gui_mode.playful {
|
||||||
|
run_playful_app();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Err(e) => print!("{e}")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ default = []
|
||||||
test = ["lazy-supplements-core/test"]
|
test = ["lazy-supplements-core/test"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
clap = { version = "4.5.38", features = ["derive"] }
|
clap.workspace = true
|
||||||
dirs = "6.0.0"
|
dirs = "6.0.0"
|
||||||
lazy-supplements-core.workspace = true
|
lazy-supplements-core.workspace = true
|
||||||
libp2p.workspace = true
|
libp2p.workspace = true
|
||||||
|
|
Loading…
Add table
Reference in a new issue