diff --git a/TODO.md b/TODO.md index f029d92..f21d7d7 100644 --- a/TODO.md +++ b/TODO.md @@ -55,7 +55,7 @@ * [ ] **Visuals** * [ ] Replace placeholder geometric shapes with actual sprites. * [ ] Add explosion animations/effects. - * [ ] Implement a scrolling starfield background. + * [x] Implement a scrolling starfield background. * [ ] **Audio** * [ ] Integrate `bevy_audio`. * [ ] Add sound effects (shooting, explosions, player death, tractor beam, etc.). diff --git a/src/components.rs b/src/components.rs index baf1ea2..fe5ff07 100644 --- a/src/components.rs +++ b/src/components.rs @@ -90,3 +90,8 @@ pub struct StartButton; #[derive(Component)] pub struct RestartMessage; + +#[derive(Component)] +pub struct Star { + pub speed: f32, +} diff --git a/src/constants.rs b/src/constants.rs index 0b2c1c0..c8e8a15 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -39,3 +39,11 @@ pub const TRACTOR_BEAM_WIDTH: f32 = 20.0; pub const TRACTOR_BEAM_DURATION: f32 = 3.0; pub const TRACTOR_BEAM_COLOR: Color = Color::rgba(0.5, 0.0, 0.8, 0.6); pub const CAPTURE_DURATION: f32 = 10.0; // How long the player stays captured + +// Starfield constants +pub const STAR_COUNT: usize = 150; +pub const STAR_MIN_SIZE: f32 = 1.0; +pub const STAR_MAX_SIZE: f32 = 3.0; +pub const STAR_MIN_SPEED: f32 = 20.0; +pub const STAR_MAX_SPEED: f32 = 100.0; +pub const STAR_Z_DEPTH: f32 = -10.0; // Behind all game entities diff --git a/src/game_state.rs b/src/game_state.rs index 8cf8b1c..fd220ed 100644 --- a/src/game_state.rs +++ b/src/game_state.rs @@ -197,11 +197,10 @@ pub fn start_menu_button_system( } pub fn handle_restart_input( - mut keyboard_input: ResMut>, + keyboard_input: Res>, mut restart_resource: ResMut, - mut app_state: ResMut>, ) { - if keyboard_input.just_pressed(KeyCode::R) { + if keyboard_input.just_pressed(KeyCode::KeyR) { restart_resource.pressed = true; } } diff --git a/src/main.rs b/src/main.rs index ea63050..af9585b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -10,6 +10,7 @@ pub mod enemy; pub mod bullet; pub mod stage; pub mod systems; +pub mod starfield; use constants::{PLAYER_RESPAWN_DELAY, STARTING_LIVES, WINDOW_HEIGHT, WINDOW_WIDTH}; use resources::{ // Added StageConfigurations @@ -36,6 +37,7 @@ use bullet::{ }; use stage::check_stage_clear; use systems::{player_exists, player_vulnerable, setup, should_respawn_player, update_window_title}; +use starfield::scroll_starfield; fn main() { App::new() @@ -115,6 +117,8 @@ fn main() { .chain() // Ensure these run in order if needed, check_formation first .run_if(in_state(AppState::Playing)), ) + // Starfield runs in all states + .add_systems(Update, scroll_starfield) // UI and state management systems .add_systems(OnEnter(AppState::StartMenu), setup_start_menu_ui) .add_systems(OnExit(AppState::StartMenu), cleanup_start_menu_ui) diff --git a/src/starfield.rs b/src/starfield.rs new file mode 100644 index 0000000..711b276 --- /dev/null +++ b/src/starfield.rs @@ -0,0 +1,48 @@ +use bevy::prelude::*; + +use crate::components::Star; +use crate::constants::{ + STAR_COUNT, STAR_MAX_SIZE, STAR_MAX_SPEED, STAR_MIN_SIZE, STAR_MIN_SPEED, + STAR_Z_DEPTH, WINDOW_HEIGHT, WINDOW_WIDTH, +}; + +pub fn spawn_starfield(commands: &mut Commands) { + for _ in 0..STAR_COUNT { + let size = fastrand::f32() * (STAR_MAX_SIZE - STAR_MIN_SIZE) + STAR_MIN_SIZE; + let speed = fastrand::f32() * (STAR_MAX_SPEED - STAR_MIN_SPEED) + STAR_MIN_SPEED; + let brightness = fastrand::f32() * 0.5 + 0.5; // 0.5 to 1.0 + + commands.spawn(( + SpriteBundle { + sprite: Sprite { + color: Color::rgb(brightness, brightness, brightness), + custom_size: Some(Vec2::new(size, size)), + ..default() + }, + transform: Transform::from_translation(Vec3::new( + fastrand::f32() * WINDOW_WIDTH - WINDOW_WIDTH / 2.0, + fastrand::f32() * WINDOW_HEIGHT - WINDOW_HEIGHT / 2.0, + STAR_Z_DEPTH, + )), + ..default() + }, + Star { speed }, + )); + } +} + +pub fn scroll_starfield(mut star_query: Query<(&mut Transform, &Star)>, time: Res