Adding some foundational UI elements

main
Elijah C. Voigt 1 year ago
parent 520df6405e
commit 3b7f626394

@ -0,0 +1,19 @@
use bevy::prelude::*;
/// Module mirroring bevy::ecs::schedule
pub(crate) mod schedule {
use super::*;
/// Module mirroring bevy::ecs::schedule::common_conditions
pub(crate) mod common_conditions {
use super::*;
/// Missing (in my opinion) condition for checking if any of a given component have changed
pub(crate) fn any_component_changed<T>(q: Query<Entity, Changed<T>>) -> bool
where
T: Component,
{
!q.is_empty()
}
}
}

@ -0,0 +1,14 @@
use crate::prelude::*;
/// Menu Plugin; empty struct for Plugin impl
pub(crate) struct DicePlugin;
impl Plugin for DicePlugin {
fn build(&self, app: &mut App) {
app.add_systems(Startup, init_dice_ui);
}
}
fn init_dice_ui(mut commands: Commands) {
todo!()
}

@ -0,0 +1,32 @@
use crate::prelude::*;
/// Dice game module
pub(crate) mod dice;
/// Menu Plugin; empty struct for Plugin impl
pub(crate) struct GamePlugin;
impl Plugin for GamePlugin {
fn build(&self, app: &mut App) {
app.init_state::<GameChoice>();
app.add_systems(Startup, init_camera);
}
}
#[derive(States, Debug, Clone, PartialEq, Eq, Hash, Default)]
enum GameChoice {
#[default]
None,
Dice,
}
/// Main game camera
fn init_camera(mut commands: Commands) {
commands.spawn(Camera2dBundle {
camera: Camera {
clear_color: ClearColorConfig::Custom(Color::WHITE),
..default()
},
..default()
});
}

@ -1,16 +1,44 @@
extern crate wee_alloc; // TODO: Should we use wee_alloc?
// Use `wee_alloc` as the global allocator. // Use `wee_alloc` as the global allocator.
#[global_allocator] #[global_allocator]
static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT; static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;
extern crate wee_alloc;
use bevy::prelude::*; /// Game Menu
pub(crate) mod menu;
/// Generic UI elements
pub(crate) mod ui;
/// Module mirroring bevy::ecs
pub(crate) mod ecs;
mod menu; /// Imports used across the project
pub(crate) mod prelude;
pub(crate) mod game;
use bevy::prelude::*;
fn main() { fn main() {
let mut app = App::new(); let mut app = App::new();
app.add_plugins(DefaultPlugins); app.add_plugins(DefaultPlugins);
app.add_plugins(menu::MenuPlugin); app.add_plugins(menu::MenuPlugin);
app.add_plugins(ui::UiPlugin);
app.add_plugins(game::GamePlugin);
app.run(); app.run();
} }
/// Hide entities with a given component
pub(crate) fn manage_visibility<SC: States + Component>(
mut q: Query<(&mut Visibility, &SC)>,
r: Res<State<SC>>,
) {
q.iter_mut().for_each(|(mut v, sc)| {
if *sc == *r.get() {
*v = Visibility::Inherited;
} else {
*v = Visibility::Hidden;
}
});
}

@ -1,67 +1,61 @@
use bevy::prelude::*; use crate::{manage_visibility, prelude::*};
/// Menu Plugin; empty struct for Plugin impl /// Menu Plugin; empty struct for Plugin impl
pub(crate) struct MenuPlugin; pub(crate) struct MenuPlugin;
impl Plugin for MenuPlugin { impl Plugin for MenuPlugin {
fn build(&self, app: &mut App) { fn build(&self, app: &mut App) {
app.init_state::<MenuState>(); app.init_state::<MenuState>();
app.add_systems(Startup, init_menu); app.add_systems(Startup, init_menu_ui);
app.add_systems(OnEnter(MenuState::Open), open_menu); app.add_systems(
app.add_systems(OnExit(MenuState::Open), close_menu); Update,
} manage_visibility::<MenuState>.run_if(state_changed::<MenuState>),
);
}
} }
/// State tracking if the menu is open or closed /// State tracking if the menu is open or closed
#[derive(States, Debug, Clone, PartialEq, Eq, Hash, Default)] #[derive(States, Debug, Clone, PartialEq, Eq, Hash, Default, Component)]
enum MenuState { enum MenuState {
#[default] #[default]
Closed, Open,
Open, Closed,
} }
#[derive(Component)]
struct MenuUi;
/// Initialize menu UI nodes at startup /// Initialize menu UI nodes at startup
fn init_menu( fn init_menu_ui(mut commands: Commands) {
mut commands: Commands, commands
) { .spawn((
commands.spawn(Camera2dBundle { ..default() }); MenuState::Open,
NodeBundle {
commands.spawn(( style: Style {
MenuUi, width: Val::Percent(100.0),
NodeBundle { height: Val::Percent(100.0),
..default() align_items: AlignItems::Center,
} align_content: AlignContent::Center,
)).with_children(|parent| { justify_items: JustifyItems::Center,
parent.spawn( justify_content: JustifyContent::Center,
ButtonBundle { flex_direction: FlexDirection::Column,
..default() ..default()
} },
).with_children(|parent| { ..default()
parent.spawn(TextBundle { },
text: Text::from_section("START", TextStyle { color: Color::BLACK, ..default() }), ))
..default() .with_children(|parent| {
}); let title_text_style = TextStyle {
}); color: Color::BLACK,
}); font_size: 24.0,
} ..default()
};
/// Make menu UI visible
fn open_menu( parent.spawn(TextBundle {
mut query: Query<&mut Visibility, With<MenuUi>>, text: Text::from_section("Game Jam Casino", title_text_style),
) { style: Style {
query.iter_mut().for_each(|mut v| { margin: UiRect::all(Val::Px(5.0)),
*v = Visibility::Hidden ..default()
}) },
} ..default()
});
/// Hide menu UI parent.spawn_empty().add(UiButton { label: "Dice" });
fn close_menu( });
mut query: Query<&mut Visibility, With<MenuUi>>,
) {
query.iter_mut().for_each(|mut v| {
*v = Visibility::Inherited
})
} }

@ -0,0 +1,7 @@
/// Bevy imports
pub(crate) use bevy::{ecs::system::EntityCommand, prelude::*};
/// Intra-project imports
pub(crate) use crate::ecs::schedule::common_conditions::*;
pub(crate) use crate::manage_visibility;
pub(crate) use crate::ui::button::UiButton;

@ -0,0 +1,57 @@
use crate::prelude::*;
/// Menu Plugin; empty struct for Plugin impl
pub(crate) struct UiPlugin;
impl Plugin for UiPlugin {
fn build(&self, app: &mut App) {
app.add_systems(
Update,
button_interaction.run_if(any_component_changed::<Interaction>),
);
}
}
fn button_interaction(mut query: Query<(&mut BackgroundColor, &Interaction)>) {
query.iter_mut().for_each(|(mut bg, i)| match i {
Interaction::Hovered => bg.0 = Color::ORANGE,
Interaction::Pressed => bg.0 = Color::GREEN,
Interaction::None => bg.0 = Color::WHITE,
});
}
pub(crate) mod button {
use super::*;
pub(crate) struct UiButton {
pub label: &'static str,
}
impl EntityCommand for UiButton {
fn apply(self, id: Entity, world: &mut World) {
let button_text_style = TextStyle {
color: Color::BLACK,
font_size: 16.0,
..default()
};
world
.entity_mut(id)
.insert(ButtonBundle {
style: Style {
margin: UiRect::all(Val::Px(5.0)),
padding: UiRect::all(Val::Px(5.0)),
border: UiRect::all(Val::Px(1.0)),
..default()
},
border_color: BorderColor(Color::BLACK),
..default()
})
.with_children(|parent| {
parent.spawn(TextBundle {
text: Text::from_section(self.label, button_text_style),
..default()
});
});
}
}
}
Loading…
Cancel
Save