use bevy::prelude::*;
use iyes_loopless::prelude::*;
use bevy::app::AppExit;
use bevy::window::close_on_esc;
use std::time::Duration;
use rand::prelude::*;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
enum GameState {
MainMenu,
InGame,
}
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_loopless_state(GameState::MainMenu)
.add_fixed_timestep(
Duration::from_millis(125),
"my_fixed_update",
)
.add_enter_system(GameState::MainMenu, setup_menu)
.add_exit_system(GameState::MainMenu, despawn_with::<MainMenu>)
.add_exit_system(GameState::InGame, despawn_with::<MySprite>)
.add_system_set(
ConditionSet::new()
.run_in_state(GameState::MainMenu)
.with_system(close_on_esc)
.with_system(butt_interact_visual)
.with_system(butt_exit.run_if(on_butt_interact::<ExitButt>))
.with_system(butt_game.run_if(on_butt_interact::<EnterButt>))
.into()
)
.add_system_set(
ConditionSet::new()
.run_in_state(GameState::InGame)
.with_system(back_to_menu_on_esc)
.with_system(clear_on_del)
.with_system(spin_sprites.run_if_not(spacebar_pressed))
.into()
)
.add_fixed_timestep_system(
"my_fixed_update", 0,
spawn_sprite
.run_in_state(GameState::InGame)
.run_if(spacebar_pressed)
)
.add_system(debug_current_state)
.add_startup_system(setup_camera)
.run();
}
#[derive(Component)]
struct MySprite;
#[derive(Component)]
struct MainMenu;
#[derive(Component)]
struct GameCamera;
#[derive(Component)]
struct ExitButt;
#[derive(Component)]
struct EnterButt;
fn clear_on_del(mut commands: Commands, kbd: Res<Input<KeyCode>>) {
if kbd.just_pressed(KeyCode::Delete) || kbd.just_pressed(KeyCode::Back) {
commands.insert_resource(NextState(GameState::InGame));
}
}
fn back_to_menu_on_esc(mut commands: Commands, kbd: Res<Input<KeyCode>>) {
if kbd.just_pressed(KeyCode::Escape) {
commands.insert_resource(NextState(GameState::MainMenu));
}
}
fn debug_current_state(state: Res<CurrentState<GameState>>) {
if state.is_changed() {
println!("Detected state change to {:?}!", state);
}
}
fn spacebar_pressed(kbd: Res<Input<KeyCode>>) -> bool {
kbd.pressed(KeyCode::Space)
}
fn despawn_with<T: Component>(mut commands: Commands, q: Query<Entity, With<T>>) {
for e in q.iter() {
commands.entity(e).despawn_recursive();
}
}
fn spawn_sprite(mut commands: Commands) {
let mut rng = thread_rng();
commands.spawn((SpriteBundle {
sprite: Sprite {
color: Color::rgba(rng.gen(), rng.gen(), rng.gen(), 0.5),
custom_size: Some(Vec2::new(64., 64.)),
..Default::default()
},
transform: Transform::from_xyz(
rng.gen_range(-420.0..420.0),
rng.gen_range(-420.0..420.0),
rng.gen_range(0.0..100.0),
),
..Default::default()
}, MySprite));
}
fn setup_camera(mut commands: Commands) {
commands.spawn((Camera2dBundle::default(), GameCamera));
}
fn spin_sprites(mut q: Query<&mut Transform, With<MySprite>>, t: Res<Time>) {
for mut transform in q.iter_mut() {
transform.rotate(Quat::from_rotation_z(1.0 * t.delta_seconds()));
}
}
fn butt_interact_visual(
mut query: Query<(&Interaction, &mut BackgroundColor), (Changed<Interaction>, With<Button>)>,
) {
for (interaction, mut color) in query.iter_mut() {
match interaction {
Interaction::Clicked => {
*color = BackgroundColor(Color::rgb(0.75, 0.75, 0.75));
}
Interaction::Hovered => {
*color = BackgroundColor(Color::rgb(0.8, 0.8, 0.8));
}
Interaction::None => {
*color = BackgroundColor(Color::rgb(1.0, 1.0, 1.0));
}
}
}
}
fn on_butt_interact<B: Component>(
query: Query<&Interaction, (Changed<Interaction>, With<Button>, With<B>)>,
) -> bool {
for interaction in query.iter() {
if *interaction == Interaction::Clicked {
return true;
}
}
false
}
fn butt_exit(mut ev: EventWriter<AppExit>) {
ev.send(AppExit);
}
fn butt_game(mut commands: Commands) {
commands.insert_resource(NextState(GameState::InGame));
}
fn setup_menu(mut commands: Commands, ass: Res<AssetServer>) {
let butt_style = Style {
justify_content: JustifyContent::Center,
align_items: AlignItems::Center,
padding: UiRect::all(Val::Px(8.0)),
margin: UiRect::all(Val::Px(4.0)),
flex_grow: 1.0,
..Default::default()
};
let butt_textstyle = TextStyle {
font: ass.load("Sansation-Regular.ttf"),
font_size: 24.0,
color: Color::BLACK,
};
let menu = commands
.spawn((NodeBundle {
background_color: BackgroundColor(Color::rgb(0.5, 0.5, 0.5)),
style: Style {
size: Size::new(Val::Auto, Val::Auto),
margin: UiRect::all(Val::Auto),
align_self: AlignSelf::Center,
flex_direction: FlexDirection::Column,
justify_content: JustifyContent::Center,
..Default::default()
},
..Default::default()
}, MainMenu))
.id();
let butt_enter = commands
.spawn((ButtonBundle {
style: butt_style.clone(),
..Default::default()
}, EnterButt))
.with_children(|btn| {
btn.spawn(TextBundle {
text: Text::from_section("Enter Game", butt_textstyle.clone()),
..Default::default()
});
})
.id();
let butt_exit = commands
.spawn((ButtonBundle {
style: butt_style.clone(),
..Default::default()
}, ExitButt))
.with_children(|btn| {
btn.spawn(TextBundle {
text: Text::from_section("Exit Game", butt_textstyle.clone()),
..Default::default()
});
})
.id();
commands
.entity(menu)
.push_children(&[butt_enter, butt_exit]);
}