use bevy::prelude::*; use std::time::Duration; pub mod components; pub mod constants; pub mod resources; pub mod game_state; pub mod player; pub mod enemy; pub mod bullet; pub mod stage; pub mod systems; pub mod starfield; use components::TractorBeam; use constants::{PLAYER_RESPAWN_DELAY, STARTING_LIVES, WINDOW_HEIGHT, WINDOW_WIDTH}; use resources::{ AttackDiveTimer, CurrentStage, EnemySpawnTimer, FormationState, PlayerLives, PlayerRespawnTimer, Score, StageConfigurations, }; use game_state::{ cleanup_game_entities, cleanup_game_over_ui, setup_game_over_ui, AppState, setup_start_menu_ui, cleanup_start_menu_ui, start_menu_button_system, handle_restart_input, restart_game_system, }; use resources::RestartPressed; use player::{ check_player_enemy_collisions, manage_invincibility, move_player, player_shoot, respawn_player, handle_captured_player, }; use enemy::{ check_formation_complete, enemy_shoot, is_formation_complete, move_enemies, spawn_enemies, trigger_attack_dives, boss_capture_attack, update_tractor_beam_visual, }; use bullet::{ check_bullet_collisions, check_enemy_bullet_player_collisions, move_bullets, move_enemy_bullets, }; use stage::check_stage_clear; use systems::{player_exists, player_vulnerable, setup, should_respawn_player, update_window_title, animate_explosion}; use starfield::scroll_starfield; pub fn run() { App::new() .insert_resource(ClearColor(Color::rgb(0.0, 0.0, 0.1))) .add_plugins(DefaultPlugins.set(WindowPlugin { primary_window: Some(Window { title: "BGLGA".into(), resolution: (WINDOW_WIDTH, WINDOW_HEIGHT).into(), resizable: false, ..default() }), ..default() })) .init_state::() .insert_resource(EnemySpawnTimer { timer: Timer::new(Duration::from_secs_f32(1.0), TimerMode::Once), }) .insert_resource(PlayerLives { count: STARTING_LIVES }) .insert_resource(PlayerRespawnTimer { timer: Timer::new( Duration::from_secs_f32(PLAYER_RESPAWN_DELAY), TimerMode::Once, ), }) .insert_resource(Score { value: 0 }) .insert_resource(CurrentStage { number: 1, waiting_for_clear: false, }) .insert_resource(FormationState { formation_complete: false, total_spawned_this_stage: 0, next_slot_index: 0, }) .insert_resource(AttackDiveTimer { timer: Timer::new(Duration::from_secs_f32(3.0), TimerMode::Once), }) .insert_resource(StageConfigurations::default()) .insert_resource(RestartPressed::default()) .add_systems(Startup, setup) .add_systems( Update, ( update_window_title, spawn_enemies, move_player.run_if(player_exists), player_shoot.run_if(player_exists), check_player_enemy_collisions.run_if(player_vulnerable), respawn_player.run_if(should_respawn_player), manage_invincibility, handle_captured_player, move_bullets, check_bullet_collisions, move_enemy_bullets, check_enemy_bullet_player_collisions.run_if(player_vulnerable), move_enemies, enemy_shoot, boss_capture_attack, update_tractor_beam_visual.run_if(any_with_component::), ) .run_if(in_state(AppState::Playing)), ) .add_systems( Update, ( check_formation_complete, trigger_attack_dives.run_if(is_formation_complete), check_stage_clear, ) .chain() .run_if(in_state(AppState::Playing)), ) .add_systems(Update, scroll_starfield) .add_systems(Update, animate_explosion) .add_systems(OnEnter(AppState::StartMenu), setup_start_menu_ui) .add_systems(OnExit(AppState::StartMenu), cleanup_start_menu_ui) .add_systems(Update, start_menu_button_system.run_if(in_state(AppState::StartMenu))) .add_systems(OnEnter(AppState::GameOver), setup_game_over_ui) .add_systems(Update, handle_restart_input.run_if(in_state(AppState::GameOver))) .add_systems(Update, restart_game_system.run_if(in_state(AppState::GameOver))) .add_systems(OnExit(AppState::Playing), cleanup_game_entities) .add_systems(OnExit(AppState::GameOver), cleanup_game_over_ui) .run(); }