From c94b61a87413a2217da12439d4d2d0b4bf3bfdd8 Mon Sep 17 00:00:00 2001 From: "Simon A. Berger" Date: Fri, 17 Nov 2023 17:22:20 +0100 Subject: [PATCH] add different gameplay modes to main menu & support game despawn --- src/game.rs | 52 +++++++++++++++++++++------- src/main.rs | 11 +++++- src/menu.rs | 98 ++++++++++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 143 insertions(+), 18 deletions(-) diff --git a/src/game.rs b/src/game.rs index f5bdbed..10badf4 100644 --- a/src/game.rs +++ b/src/game.rs @@ -13,19 +13,29 @@ use crate::{ prelude::*, ship::{ShipBundle, SHIP_VERTICES}, state::GameState, - CmdlineArgs, }; -pub struct GamePlugin; +#[derive(Resource)] +pub struct GameSpawnInfo { + pub spawn_player_ship: bool, + pub spawn_player_droid: bool, + pub spawn_player_jnr: bool, + pub spawn_enemy_droids: u32, + pub spawn_benchmark: bool, + pub gravity: bool, +} + +#[derive(Component)] +pub struct GameMarker; -fn game_setup(mut commands: Commands, args: Res) { +fn game_setup(mut commands: Commands, spawn_info: Res) { let shape = shapes::RegularPolygon { sides: 6, feature: shapes::RegularPolygonFeature::Radius(32.0), ..shapes::RegularPolygon::default() }; - let player = if args.ship { + let player = if spawn_info.spawn_player_ship { let ship_shape = shapes::Polygon { points: SHIP_VERTICES.into(), closed: true, @@ -46,8 +56,9 @@ fn game_setup(mut commands: Commands, args: Res) { .insert(default_stroke(YELLOW_HDR)) .insert(InputTarget) .insert(CameraTarget) + .insert(GameMarker) .id() - } else if args.hexton { + } else if spawn_info.spawn_player_jnr { let hexton_shape = shapes::Polygon { points: HEXTON_VERTICES.into(), closed: true, @@ -68,8 +79,9 @@ fn game_setup(mut commands: Commands, args: Res) { .insert(default_stroke(BLUE_HDR)) .insert(InputTarget) .insert(CameraTarget) + .insert(GameMarker) .id() - } else if args.benchmark { + } else if spawn_info.spawn_benchmark { commands .spawn(SpatialBundle { transform: Transform::from_translation(Vec3::new(100.0, 142.0, 0.0)), @@ -86,13 +98,14 @@ fn game_setup(mut commands: Commands, args: Res) { color_generator: ColorGenerator::Static(7), }) .insert(CameraTarget) + .insert(GameMarker) .id() // - } else { + } else if spawn_info.spawn_player_droid { let my_shape_builder = GeometryBuilder::build_as(&shape); commands - .spawn(DroidBundle::new("player", args.gravity)) + .spawn(DroidBundle::new("player", spawn_info.gravity)) .insert(PlayerDroidBundle::default()) .insert(ShapeBundle { path: my_shape_builder, @@ -103,6 +116,7 @@ fn game_setup(mut commands: Commands, args: Res) { ..default() }) .insert(default_stroke(GREEN_HDR)) + .insert(GameMarker) // .insert(ParticleSource { // rate: 1000, // direction: ParticleDirection::Uniform, @@ -112,33 +126,47 @@ fn game_setup(mut commands: Commands, args: Res) { // lifetime_spread: 0.5, // }) .id() + } else { + panic!("dont know what to spawn"); }; - if !args.no_droid { + let mut enemy_offset = Vec3::new(-100.0, 100.0, 0.0); + for _ in 0..spawn_info.spawn_enemy_droids { let enemy_shape_builder = GeometryBuilder::build_as(&shape); commands - .spawn(DroidBundle::new("r2d2", args.gravity)) + .spawn(DroidBundle::new("r2d2", spawn_info.gravity)) // .insert_bundle(AiDroidBundle::with_enemy(enemy)) .insert(AiDroidBundle::with_enemy(player)) .insert(ShapeBundle { path: enemy_shape_builder, spatial: SpatialBundle { - transform: Transform::from_translation(Vec3::new(-100.0, 100.0, 0.0)), + transform: Transform::from_translation(enemy_offset), ..default() }, ..default() }) .insert(default_stroke(RED_HDR)) + .insert(GameMarker) .insert(new_shooting_droid_ai()); + enemy_offset.x += 100.0; commands.spawn_empty().insert(Portal { tile_pos: TilePos(Hex::new(5, -1)), timer: Timer::from_seconds(2.0, TimerMode::Repeating), }); } } + +// Generic system that takes a component as a parameter, and will despawn all entities with that component +fn despawn_screen(to_despawn: Query>, mut commands: Commands) { + for entity in &to_despawn { + commands.entity(entity).despawn_recursive(); + } +} +pub struct GamePlugin; impl Plugin for GamePlugin { fn build(&self, app: &mut App) { - app.add_systems(OnExit(GameState::None), game_setup); + app.add_systems(OnExit(GameState::None), game_setup) + .add_systems(OnEnter(GameState::None), despawn_screen::); } } diff --git a/src/main.rs b/src/main.rs index d17e23f..48f2780 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,15 +3,24 @@ use bevy::prelude::*; use bevy_rapier2d::prelude::*; use clap::Parser; -use hexadroid::CmdlineArgs; +use hexadroid::{game::GameSpawnInfo, CmdlineArgs}; fn main() { let args = CmdlineArgs::parse(); + let spawn_info = GameSpawnInfo { + spawn_player_ship: args.ship, + spawn_player_droid: !args.ship && !args.hexton, + spawn_player_jnr: args.hexton, + spawn_enemy_droids: if args.no_droid { 0 } else { 1 }, + spawn_benchmark: args.benchmark, + gravity: args.gravity, + }; let mut app = App::new(); // bevy plugins app.add_plugins(DefaultPlugins) .insert_resource(ClearColor(Color::BLACK)) + .insert_resource(spawn_info) .insert_resource(Msaa::default()); app.add_plugins(hexadroid::DefaultPlugins::new(args.clone())); //default().with_debug_draw(args.debug_draw)); diff --git a/src/menu.rs b/src/menu.rs index a7f732a..c653774 100644 --- a/src/menu.rs +++ b/src/menu.rs @@ -1,6 +1,6 @@ use bevy::{app::AppExit, prelude::*}; -use crate::state::GameState; +use crate::{game::GameSpawnInfo, state::GameState}; // Tag component used to tag entities added on the main menu screen #[derive(Component)] struct OnMainMenuScreen; @@ -25,7 +25,10 @@ const TEXT_COLOR: Color = Color::rgb(0.9, 0.9, 0.9); // All actions that can be triggered from a button click #[derive(Component)] enum MenuButtonAction { - Play, + PlayDroid, + PlayShip, + PlayHexton, + DropGame, // Settings, // SettingsDisplay, // SettingsSound, @@ -121,7 +124,7 @@ fn main_menu_setup(mut commands: Commands, asset_server: Res) { background_color: NORMAL_BUTTON.into(), ..default() }, - MenuButtonAction::Play, + MenuButtonAction::PlayDroid, )) .with_children(|parent| { let icon = asset_server.load("textures/Game Icons/right.png"); @@ -131,7 +134,70 @@ fn main_menu_setup(mut commands: Commands, asset_server: Res) { ..default() }); parent.spawn(TextBundle::from_section( - "New Game", + "Play Droid", + button_text_style.clone(), + )); + }); + parent + .spawn(( + ButtonBundle { + style: button_style.clone(), + background_color: NORMAL_BUTTON.into(), + ..default() + }, + MenuButtonAction::PlayShip, + )) + .with_children(|parent| { + let icon = asset_server.load("textures/Game Icons/right.png"); + parent.spawn(ImageBundle { + style: button_icon_style.clone(), + image: UiImage::new(icon), + ..default() + }); + parent.spawn(TextBundle::from_section( + "Play Ship", + button_text_style.clone(), + )); + }); + parent + .spawn(( + ButtonBundle { + style: button_style.clone(), + background_color: NORMAL_BUTTON.into(), + ..default() + }, + MenuButtonAction::PlayHexton, + )) + .with_children(|parent| { + let icon = asset_server.load("textures/Game Icons/right.png"); + parent.spawn(ImageBundle { + style: button_icon_style.clone(), + image: UiImage::new(icon), + ..default() + }); + parent.spawn(TextBundle::from_section( + "Play Cmdr", + button_text_style.clone(), + )); + }); + parent + .spawn(( + ButtonBundle { + style: button_style.clone(), + background_color: NORMAL_BUTTON.into(), + ..default() + }, + MenuButtonAction::DropGame, + )) + .with_children(|parent| { + let icon = asset_server.load("textures/Game Icons/right.png"); + parent.spawn(ImageBundle { + style: button_icon_style.clone(), + image: UiImage::new(icon), + ..default() + }); + parent.spawn(TextBundle::from_section( + "Drop game", button_text_style.clone(), )); }); @@ -187,14 +253,36 @@ fn menu_action( mut app_exit_events: EventWriter, mut menu_state: ResMut>, mut game_state: ResMut>, + mut spawn_info: ResMut, ) { for (interaction, menu_button_action) in &interaction_query { if *interaction == Interaction::Pressed { match menu_button_action { MenuButtonAction::Quit => app_exit_events.send(AppExit), - MenuButtonAction::Play => { + MenuButtonAction::PlayDroid => { + game_state.set(GameState::Game); + menu_state.set(MenuState::Disabled); + spawn_info.spawn_player_droid = true; + spawn_info.spawn_player_ship = false; + spawn_info.spawn_player_jnr = false; + } + MenuButtonAction::PlayShip => { + game_state.set(GameState::Game); + menu_state.set(MenuState::Disabled); + spawn_info.spawn_player_droid = false; + spawn_info.spawn_player_ship = true; + spawn_info.spawn_player_jnr = false; + } + MenuButtonAction::PlayHexton => { game_state.set(GameState::Game); menu_state.set(MenuState::Disabled); + spawn_info.spawn_player_droid = false; + spawn_info.spawn_player_ship = false; + spawn_info.spawn_player_jnr = true; + } + MenuButtonAction::DropGame => { + game_state.set(GameState::None); + menu_state.set(MenuState::Main); } // MenuButtonAction::Settings => menu_state.set(MenuState::Settings), // MenuButtonAction::SettingsDisplay => { // menu_state.set(MenuState::SettingsDisplay);