Adding some foundational UI elements
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…
Reference in New Issue