add main menu
This commit is contained in:
parent
0d945de135
commit
e5f87736df
5 changed files with 230 additions and 66 deletions
|
@ -10,7 +10,7 @@ use rand::Rng;
|
||||||
use crate::{
|
use crate::{
|
||||||
player::{LifeChangeEvent, Player},
|
player::{LifeChangeEvent, Player},
|
||||||
scene::SceneObj,
|
scene::SceneObj,
|
||||||
METER,
|
GameState, GameplaySet, METER,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Component)]
|
#[derive(Component)]
|
||||||
|
@ -28,7 +28,7 @@ pub fn spawner_plugin(app: &mut App) {
|
||||||
app.add_plugins(EntropyPlugin::<WyRand>::default())
|
app.add_plugins(EntropyPlugin::<WyRand>::default())
|
||||||
.add_event::<CrateDropEvent>()
|
.add_event::<CrateDropEvent>()
|
||||||
.add_event::<CrateCollision>()
|
.add_event::<CrateCollision>()
|
||||||
.add_systems(Startup, add_timer)
|
.add_systems(OnEnter(GameState::InGame), add_timer.in_set(GameplaySet))
|
||||||
.add_systems(
|
.add_systems(
|
||||||
Update,
|
Update,
|
||||||
(
|
(
|
||||||
|
@ -37,7 +37,8 @@ pub fn spawner_plugin(app: &mut App) {
|
||||||
crate_collisions,
|
crate_collisions,
|
||||||
delete_on_env_coll,
|
delete_on_env_coll,
|
||||||
player_coll,
|
player_coll,
|
||||||
),
|
)
|
||||||
|
.in_set(GameplaySet),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
57
src/game_state.rs
Normal file
57
src/game_state.rs
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
use bevy::{prelude::*, time::Stopwatch};
|
||||||
|
|
||||||
|
use crate::GameplaySet;
|
||||||
|
|
||||||
|
#[derive(Component)]
|
||||||
|
pub struct GameState {
|
||||||
|
game_time: Stopwatch,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Component)]
|
||||||
|
struct StateText;
|
||||||
|
|
||||||
|
pub fn state_and_ui_plugin(app: &mut App) {
|
||||||
|
app.add_systems(
|
||||||
|
OnEnter(crate::GameState::InGame),
|
||||||
|
(setup_gamestate, setup_ui).in_set(GameplaySet),
|
||||||
|
)
|
||||||
|
.add_systems(Update, (update_time).in_set(GameplaySet));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn setup_gamestate(mut commands: Commands) {
|
||||||
|
commands.spawn(GameState {
|
||||||
|
game_time: Stopwatch::new(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn setup_ui(mut commands: Commands) {
|
||||||
|
commands.spawn((
|
||||||
|
TextBundle::from_sections([
|
||||||
|
TextSection::new("Score: ", TextStyle::default()),
|
||||||
|
TextSection::new("0", TextStyle::default()),
|
||||||
|
])
|
||||||
|
.with_style(Style {
|
||||||
|
position_type: PositionType::Absolute,
|
||||||
|
top: Val::Px(5.0),
|
||||||
|
right: Val::Px(5.0),
|
||||||
|
..default()
|
||||||
|
}),
|
||||||
|
StateText,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_time(
|
||||||
|
mut state_txt: Query<&mut Text, With<StateText>>,
|
||||||
|
mut game_state: Query<&mut GameState>,
|
||||||
|
time: Res<Time>,
|
||||||
|
) {
|
||||||
|
let mut txt = state_txt.single_mut();
|
||||||
|
let time = game_state
|
||||||
|
.single_mut()
|
||||||
|
.game_time
|
||||||
|
.tick(time.delta())
|
||||||
|
.elapsed_secs()
|
||||||
|
* 100.;
|
||||||
|
|
||||||
|
txt.sections[1].value = format!("{time:.0}");
|
||||||
|
}
|
85
src/main.rs
85
src/main.rs
|
@ -1,12 +1,24 @@
|
||||||
|
use crate::main_menu::main_menu_plugin;
|
||||||
use bevy::{
|
use bevy::{
|
||||||
prelude::*,
|
prelude::*,
|
||||||
sprite::{MaterialMesh2dBundle, Mesh2dHandle},
|
sprite::{MaterialMesh2dBundle, Mesh2dHandle},
|
||||||
};
|
};
|
||||||
use bevy_rapier2d::prelude::*;
|
use bevy_rapier2d::prelude::*;
|
||||||
use drops::spawner_plugin;
|
use drops::spawner_plugin;
|
||||||
|
use main_menu::MainMenuSet;
|
||||||
use player::LifeChangeEvent;
|
use player::LifeChangeEvent;
|
||||||
|
|
||||||
const METER: f32 = 48.;
|
const METER: f32 = 48.;
|
||||||
|
|
||||||
|
#[derive(SystemSet, Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
|
struct GameplaySet;
|
||||||
|
|
||||||
|
#[derive(States, Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
|
enum GameState {
|
||||||
|
MainMenu,
|
||||||
|
InGame,
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut rapier_config = RapierConfiguration::new(METER * 2.5);
|
let mut rapier_config = RapierConfiguration::new(METER * 2.5);
|
||||||
rapier_config.timestep_mode = TimestepMode::Variable {
|
rapier_config.timestep_mode = TimestepMode::Variable {
|
||||||
|
@ -18,14 +30,24 @@ fn main() {
|
||||||
.add_plugins(DefaultPlugins)
|
.add_plugins(DefaultPlugins)
|
||||||
// this does things with gravity
|
// this does things with gravity
|
||||||
.insert_resource(rapier_config)
|
.insert_resource(rapier_config)
|
||||||
|
.insert_state(GameState::MainMenu)
|
||||||
.add_plugins(RapierPhysicsPlugin::<NoUserData>::pixels_per_meter(METER))
|
.add_plugins(RapierPhysicsPlugin::<NoUserData>::pixels_per_meter(METER))
|
||||||
.add_plugins(RapierDebugRenderPlugin::default())
|
.add_plugins(RapierDebugRenderPlugin::default())
|
||||||
.add_plugins((
|
.add_plugins((
|
||||||
|
main_menu_plugin,
|
||||||
spawner_plugin,
|
spawner_plugin,
|
||||||
game_state::state_and_ui_plugin,
|
game_state::state_and_ui_plugin,
|
||||||
player::player_plugin,
|
player::player_plugin,
|
||||||
))
|
))
|
||||||
.add_systems(Startup, (scene::setup_scene, setup_cam))
|
.add_systems(Startup, setup_cam)
|
||||||
|
.add_systems(OnEnter(GameState::InGame), scene::setup_scene)
|
||||||
|
.configure_sets(
|
||||||
|
Update,
|
||||||
|
(
|
||||||
|
GameplaySet.run_if(in_state(GameState::InGame)),
|
||||||
|
MainMenuSet.run_if(in_state(GameState::MainMenu)),
|
||||||
|
),
|
||||||
|
)
|
||||||
.run()
|
.run()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,64 +59,7 @@ fn setup_cam(mut commands: Commands) {
|
||||||
}
|
}
|
||||||
|
|
||||||
mod drops;
|
mod drops;
|
||||||
|
mod game_state;
|
||||||
|
mod main_menu;
|
||||||
mod player;
|
mod player;
|
||||||
mod scene;
|
mod scene;
|
||||||
mod game_state {
|
|
||||||
use bevy::{prelude::*, time::Stopwatch};
|
|
||||||
|
|
||||||
#[derive(Component)]
|
|
||||||
pub struct GameState {
|
|
||||||
score: u32,
|
|
||||||
game_time: Stopwatch,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Component)]
|
|
||||||
struct StateText;
|
|
||||||
|
|
||||||
pub fn state_and_ui_plugin(app: &mut App) {
|
|
||||||
app.add_systems(Startup, (setup_gamestate, setup_ui))
|
|
||||||
.add_systems(Update, (update_time));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn setup_gamestate(mut commands: Commands) {
|
|
||||||
commands.spawn(GameState {
|
|
||||||
score: 0,
|
|
||||||
game_time: Stopwatch::new(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
fn setup_ui(mut commands: Commands) {
|
|
||||||
commands.spawn((
|
|
||||||
TextBundle::from_sections([
|
|
||||||
TextSection::new("Score: ", TextStyle::default()),
|
|
||||||
TextSection::new("0", TextStyle::default()),
|
|
||||||
TextSection::new("\n", TextStyle::default()),
|
|
||||||
TextSection::new("Time: ", TextStyle::default()),
|
|
||||||
TextSection::new("0", TextStyle::default()),
|
|
||||||
TextSection::new("s", TextStyle::default()),
|
|
||||||
])
|
|
||||||
.with_style(Style {
|
|
||||||
position_type: PositionType::Absolute,
|
|
||||||
top: Val::Px(5.0),
|
|
||||||
right: Val::Px(5.0),
|
|
||||||
..default()
|
|
||||||
}),
|
|
||||||
StateText,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn update_time(
|
|
||||||
mut state_txt: Query<&mut Text, With<StateText>>,
|
|
||||||
mut game_state: Query<&mut GameState>,
|
|
||||||
time: Res<Time>,
|
|
||||||
) {
|
|
||||||
let mut txt = state_txt.single_mut();
|
|
||||||
let time = game_state
|
|
||||||
.single_mut()
|
|
||||||
.game_time
|
|
||||||
.tick(time.delta())
|
|
||||||
.elapsed_secs();
|
|
||||||
|
|
||||||
txt.sections[4].value = format!("{time:.2}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
135
src/main_menu.rs
Normal file
135
src/main_menu.rs
Normal file
|
@ -0,0 +1,135 @@
|
||||||
|
use bevy::{app::AppExit, prelude::*};
|
||||||
|
|
||||||
|
use crate::GameState;
|
||||||
|
|
||||||
|
#[derive(SystemSet, Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
|
pub struct MainMenuSet;
|
||||||
|
|
||||||
|
pub fn main_menu_plugin(app: &mut App) {
|
||||||
|
app.add_systems(
|
||||||
|
OnEnter(GameState::MainMenu),
|
||||||
|
setup_main_menu_ui.in_set(MainMenuSet),
|
||||||
|
)
|
||||||
|
.add_systems(
|
||||||
|
Update,
|
||||||
|
(button_color_system, button_action).in_set(MainMenuSet),
|
||||||
|
)
|
||||||
|
.add_systems(OnExit(GameState::MainMenu), exit_menu.in_set(MainMenuSet));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Component)]
|
||||||
|
struct MainMenu;
|
||||||
|
|
||||||
|
#[derive(Component)]
|
||||||
|
enum MenuButtonAction {
|
||||||
|
Play,
|
||||||
|
Quit,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn setup_main_menu_ui(mut commands: Commands) {
|
||||||
|
commands
|
||||||
|
.spawn((
|
||||||
|
NodeBundle {
|
||||||
|
style: Style {
|
||||||
|
align_items: AlignItems::Center,
|
||||||
|
justify_content: JustifyContent::Center,
|
||||||
|
|
||||||
|
flex_direction: FlexDirection::Column,
|
||||||
|
width: Val::Percent(100.0),
|
||||||
|
height: Val::Percent(100.0),
|
||||||
|
..default()
|
||||||
|
},
|
||||||
|
..default()
|
||||||
|
},
|
||||||
|
MainMenu,
|
||||||
|
))
|
||||||
|
.with_children(|parent| {
|
||||||
|
parent.spawn(TextBundle::from_section(
|
||||||
|
"Ev4der",
|
||||||
|
TextStyle {
|
||||||
|
font_size: 144.,
|
||||||
|
..default()
|
||||||
|
},
|
||||||
|
));
|
||||||
|
let btn_style = Style {
|
||||||
|
width: Val::Px(300.0),
|
||||||
|
height: Val::Px(80.0),
|
||||||
|
margin: UiRect::all(Val::Px(20.0)),
|
||||||
|
|
||||||
|
justify_content: JustifyContent::Center,
|
||||||
|
align_items: AlignItems::Center,
|
||||||
|
..default()
|
||||||
|
};
|
||||||
|
let btn_txt_style = TextStyle {
|
||||||
|
font_size: 64.,
|
||||||
|
..default()
|
||||||
|
};
|
||||||
|
parent
|
||||||
|
.spawn((
|
||||||
|
ButtonBundle {
|
||||||
|
style: btn_style.clone(),
|
||||||
|
background_color: Color::rgb(0.3, 0.3, 0.3).into(),
|
||||||
|
..default()
|
||||||
|
},
|
||||||
|
MenuButtonAction::Play,
|
||||||
|
))
|
||||||
|
.with_children(|parent| {
|
||||||
|
parent.spawn(TextBundle::from_section("Play!", btn_txt_style.clone()));
|
||||||
|
});
|
||||||
|
parent
|
||||||
|
.spawn((
|
||||||
|
ButtonBundle {
|
||||||
|
style: btn_style.clone(),
|
||||||
|
background_color: Color::rgb(0.3, 0.3, 0.3).into(),
|
||||||
|
..default()
|
||||||
|
},
|
||||||
|
MenuButtonAction::Quit,
|
||||||
|
))
|
||||||
|
.with_children(|parent| {
|
||||||
|
parent.spawn(TextBundle::from_section("Quit :(", btn_txt_style.clone()));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn exit_menu(to_despawn: Query<Entity, With<MainMenu>>, mut commands: Commands) {
|
||||||
|
for e in &to_despawn {
|
||||||
|
commands.entity(e).despawn_recursive();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn button_color_system(
|
||||||
|
mut interaction_query: Query<
|
||||||
|
(&Interaction, &mut BackgroundColor),
|
||||||
|
(Changed<Interaction>, With<Button>),
|
||||||
|
>,
|
||||||
|
) {
|
||||||
|
for (interaction, mut color) in &mut interaction_query {
|
||||||
|
*color = match *interaction {
|
||||||
|
Interaction::Pressed => Color::rgb(0.4, 0.4, 0.4).into(),
|
||||||
|
Interaction::Hovered => Color::rgb(0.2, 0.2, 0.2).into(),
|
||||||
|
Interaction::None => Color::rgb(0.3, 0.3, 0.3).into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn button_action(
|
||||||
|
interaction_query: Query<
|
||||||
|
(&Interaction, &MenuButtonAction),
|
||||||
|
(Changed<Interaction>, With<Button>),
|
||||||
|
>,
|
||||||
|
mut ev_exit: EventWriter<AppExit>,
|
||||||
|
mut game_state: ResMut<NextState<GameState>>,
|
||||||
|
) {
|
||||||
|
for (interaction, action) in &interaction_query {
|
||||||
|
if *interaction == Interaction::Pressed {
|
||||||
|
match action {
|
||||||
|
MenuButtonAction::Quit => {
|
||||||
|
ev_exit.send(AppExit);
|
||||||
|
}
|
||||||
|
MenuButtonAction::Play => {
|
||||||
|
game_state.set(GameState::InGame);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,7 +5,7 @@ use bevy::{
|
||||||
};
|
};
|
||||||
use bevy_rapier2d::prelude::*;
|
use bevy_rapier2d::prelude::*;
|
||||||
|
|
||||||
use crate::METER;
|
use crate::{GameState, GameplaySet, METER};
|
||||||
|
|
||||||
#[derive(Component)]
|
#[derive(Component)]
|
||||||
pub struct Player {
|
pub struct Player {
|
||||||
|
@ -24,8 +24,14 @@ const DEFAULT_LIVES: u8 = 5;
|
||||||
|
|
||||||
pub fn player_plugin(app: &mut App) {
|
pub fn player_plugin(app: &mut App) {
|
||||||
app.add_event::<LifeChangeEvent>()
|
app.add_event::<LifeChangeEvent>()
|
||||||
.add_systems(Startup, (add_player, add_lives_ui))
|
.add_systems(
|
||||||
.add_systems(Update, (move_player, player_ground_collision, update_lives));
|
OnEnter(GameState::InGame),
|
||||||
|
(add_player, add_lives_ui).in_set(GameplaySet),
|
||||||
|
)
|
||||||
|
.add_systems(
|
||||||
|
Update,
|
||||||
|
(move_player, player_ground_collision, update_lives).in_set(GameplaySet),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_player(
|
pub fn add_player(
|
||||||
|
|
Loading…
Reference in a new issue