diff --git a/src/states/level/components.rs b/src/states/level/components.rs index 47b5660..2050aca 100644 --- a/src/states/level/components.rs +++ b/src/states/level/components.rs @@ -39,7 +39,6 @@ pub struct WaveState { pub ball_reached_end: bool, pub is_warming_up: bool, pub is_queue_locked: bool, //отдельно для большей явности - pub last_insert_index: Option, //для системы удаления серий шариков } impl Default for WaveState { @@ -49,7 +48,6 @@ impl Default for WaveState { ball_reached_end: false, is_warming_up: false, is_queue_locked: false, - last_insert_index: None, } } } @@ -67,8 +65,4 @@ pub enum Direction { Bottom, } -#[derive(Resource, Default, Debug)] -pub struct Score(pub u32); -#[derive(Component)] -pub struct ScoreTextMarker; diff --git a/src/states/level/components_ball.rs b/src/states/level/components_ball.rs index 77bc7ef..c5af0ed 100644 --- a/src/states/level/components_ball.rs +++ b/src/states/level/components_ball.rs @@ -1,13 +1,6 @@ use bevy::prelude::*; use rand::seq::IndexedRandom; -#[derive(Component, Debug, Clone, Copy)] -pub struct Ball { - pub ball_type: BallType, - pub slot_index: usize, - pub slot_progress: f32, -} - #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)] pub enum BallType { #[default] @@ -35,3 +28,9 @@ impl BallType { } } +#[derive(Component, Debug)] +pub struct Ball { + pub ball_type: BallType, + pub slot_index: usize, + pub slot_progress: f32, +} \ No newline at end of file diff --git a/src/states/level/components_cannon.rs b/src/states/level/components_cannon.rs index 6113c20..fc40ee8 100644 --- a/src/states/level/components_cannon.rs +++ b/src/states/level/components_cannon.rs @@ -27,6 +27,12 @@ impl CannonState { } pub fn cycle_next(&mut self) { + // self.next_type = match self.next_type { + // BallType::First => BallType::Second, + // BallType::Second => BallType::Third, + // BallType::Third => BallType::Forth, + // BallType::Forth => BallType::First, + // }; let cur = self.current_type; self.current_type = self.next_type; self.next_type = cur; diff --git a/src/states/level/constants.rs b/src/states/level/constants.rs deleted file mode 100644 index b108631..0000000 --- a/src/states/level/constants.rs +++ /dev/null @@ -1,14 +0,0 @@ -use crate::FACTOR; - -pub const SHIFT: f32 = 1.0; // коэффициент пересчета для слотов -pub const SLOT_SIZE: f32 = FACTOR as f32 / SHIFT; - -pub const BALL_MOVEMENT_SPEED: f32 = 60.0; // пикселей в секунду -pub const INITIAL_BALLS_COUNT: usize = 10; -pub const WARMUP_BALL_MOVEMENT_MULTIPLIER: f32 = 5.0; // во сколько раз больше BALL_MOVEMENT_SPEED - -// Z-индексы элементов -pub const CANNON_Z_INDEX: f32 = 10.0; -pub const PROJECTILE_Z_INDEX: f32 = 11.0; -pub const CURRENT_SHOT_Z_INDEX: f32 = 12.0; -pub const NEXT_SHOT_Z_INDEX: f32 = 12.0; \ No newline at end of file diff --git a/src/states/level/mod.rs b/src/states/level/mod.rs index e9b663c..671aa49 100644 --- a/src/states/level/mod.rs +++ b/src/states/level/mod.rs @@ -18,9 +18,3 @@ mod components_cannon; pub use components_cannon::*; mod components_ball; pub use components_ball::*; -mod ui; -pub use ui::*; -mod constants; -pub use constants::*; - - diff --git a/src/states/level/plugin.rs b/src/states/level/plugin.rs index 52e3f73..8afb31b 100644 --- a/src/states/level/plugin.rs +++ b/src/states/level/plugin.rs @@ -2,40 +2,36 @@ use crate::states::AppState::GameState; use crate::states::level::*; use bevy::prelude::*; + pub struct LevelPlugin; impl Plugin for LevelPlugin { fn build(&self, app: &mut App) { - app.add_systems( - OnEnter(GameState), - (setup_level, initialize_queue, setup_cannon).chain(), - ) - .add_systems( - Update, - ( - // debug_draw_grid, - debug_draw_track, - warmup_queue_movement, //до спавна остальных шариков - spawn_new_ball, - check_wave_completion, - //cannon systems - cycle_cannon_type, - update_cannon_preview, - spawn_projectile_from_cannon, - //сохранять порядок верхних трех - rotate_cannon, - move_projectiles, - //сохраняем порядок трех + app.add_systems(OnEnter(GameState), ( + setup_level, + initialize_queue, + setup_cannon).chain()) + .add_systems( + Update, ( - detect_projectile_hit, - check_and_remove_matches, + // debug_draw_grid, + debug_draw_track, + warmup_queue_movement, //до спавна остальных шариков + spawn_new_ball, move_queue_along_track, + check_wave_completion, + //cannon systems + cycle_cannon_type, + update_cannon_preview, + spawn_projectile_from_cannon, + //сохранять порядок верхних трех + rotate_cannon, + move_projectiles, + detect_projectile_hit, ) - .chain(), + .run_if(in_state(GameState)), ) - .run_if(in_state(GameState)), - ) - .add_systems(OnExit(GameState), cleanup_main_menu); + .add_systems(OnExit(GameState), cleanup_main_menu); } } @@ -44,4 +40,4 @@ fn cleanup_main_menu(mut commands: Commands, query: Query, @@ -58,7 +64,7 @@ pub fn move_queue_along_track( for (mut ball, mut transform) in balls.iter_mut() { // Увеличиваем прогресс - ball.slot_progress += BALL_MOVEMENT_SPEED * time.delta_secs() / SLOT_SIZE; + ball.slot_progress += SPEED * time.delta_secs() / SLOT_SIZE; // Если шарик достиг конца текущего сегмента if ball.slot_progress >= 1.0 { @@ -86,7 +92,8 @@ pub fn move_queue_along_track( } } - +// FIXME перенести позже в более удобное место/объект левела +const START_COUNT: usize = 10; pub fn initialize_queue( mut commands: Commands, @@ -95,16 +102,16 @@ pub fn initialize_queue( mut wave: ResMut, ) { // заполняем слоты от -START_COUNT до -1 - let base_idx = track.spawn_index.saturating_sub(INITIAL_BALLS_COUNT); + let base_idx = track.spawn_index.saturating_sub(START_COUNT); - for i in 0..INITIAL_BALLS_COUNT { + for i in 0..START_COUNT { let slot_idx = base_idx + i; // пропускаем индекс 0 (спавн за экраном) let Some(&pos) = track.points.get(slot_idx) else { continue; }; println!("Slot {}: {:?}", slot_idx, pos); //debug - let target_idx = slot_idx + INITIAL_BALLS_COUNT; + let target_idx = slot_idx + START_COUNT; let ball_type = BallType::random(); let image: Handle = asset_server.load(ball_type.asset_path()); @@ -129,7 +136,8 @@ pub fn initialize_queue( wave.spawning_allowed = false; } - +// FIXME перенести позже в более удобное место/объект левела +const WARMUP_MULTIPLIER: f32 = 5.0; pub fn warmup_queue_movement( track: Res, mut wave: ResMut, @@ -141,7 +149,7 @@ pub fn warmup_queue_movement( ) { if !wave.is_warming_up { return; } - let speed = BALL_MOVEMENT_SPEED * WARMUP_BALL_MOVEMENT_MULTIPLIER; + let speed = SPEED * WARMUP_MULTIPLIER; let spawn_slot = track.spawn_index.saturating_sub(1); @@ -201,82 +209,3 @@ pub fn check_wave_completion( } } -pub fn check_and_remove_matches( - mut commands: Commands, - mut wave: ResMut, - mut balls: ParamSet<( - Query<(Entity, &Ball)>, - Query<(Entity, &mut Ball)> - )>, - mut score: ResMut, -) { - let Some(insert_idx) = wave.last_insert_index.take() else { return; }; - - let mut balls_sorted: Vec<(Entity, Ball)> = balls.p0() - .iter() - .map(|(e, b)| (e, *b)) - .collect(); - balls_sorted.sort_by_key(|(_, b)| b.slot_index); - - if balls_sorted.is_empty() { return; } - - let Some(pos) = balls_sorted.iter().position(|(_, b)| b.slot_index == insert_idx) else { return; }; - let inserted_ball = balls_sorted[pos].1; - - // Ищем группу того же типа - let mut group_start = pos; - while group_start > 0 && balls_sorted[group_start - 1].1.ball_type == inserted_ball.ball_type { - group_start -= 1; - } - - let mut group_end = pos + 1; - while group_end < balls_sorted.len() && balls_sorted[group_end].1.ball_type == inserted_ball.ball_type { - group_end += 1; - } - - let group_size = group_end - group_start; - if group_size < 3 { return; } - - // Запоминаем диапазон до удаления - let removed_min_idx = balls_sorted[group_start].1.slot_index; - let removed_max_idx = balls_sorted[group_end - 1].1.slot_index; - let removed_count = group_size; - - // Проверяем соседей - let has_left_neighbors = balls_sorted.iter().any(|(_, b)| b.slot_index < removed_min_idx); - let has_right_neighbors = balls_sorted.iter().any(|(_, b)| b.slot_index > removed_max_idx); - - // --- УДАЛЕНИЕ --- - let to_remove: Vec = balls_sorted[group_start..group_end] - .iter() - .map(|(e, _)| *e) - .collect(); - - for entity in to_remove.iter() { - commands.entity(*entity).despawn(); - } - - let gained = removed_count * 100; - score.0 += gained as u32; - println!("Match at idx {}! +{} points | total: {}", insert_idx, gained, score.0); - - // --- СХЛОПЫВАНИЕ ОЧЕРЕДИ --- - - if has_left_neighbors && has_right_neighbors { - // 🔸 Удаление ВНУТРИ: сдвигаем все шарики СПРАВА влево - println!("Closing gap ({}..{}), shifting right balls left by {}", - removed_min_idx, removed_max_idx, removed_count); - - // Сдвигаем индексы всех шариков с index > removed_max_idx - for (entity, mut ball) in balls.p1().iter_mut() { - if ball.slot_index > removed_max_idx { - ball.slot_index -= removed_count; - ball.slot_progress = 0.0; // "Примагничиваем" к новому слоту - } - } - return; - } - - // 🔸 Удаление в НАЧАЛЕ или КОНЦЕ: индексы не меняем - // (опционально: можно сбросить progress у правых соседей для чёткости) -} \ No newline at end of file diff --git a/src/states/level/system_cannon.rs b/src/states/level/system_cannon.rs index b8ad981..b63ed66 100644 --- a/src/states/level/system_cannon.rs +++ b/src/states/level/system_cannon.rs @@ -2,6 +2,11 @@ use bevy::prelude::*; use crate::states::level::*; use bevy::window::PrimaryWindow; +const CANNON_Z_INDEX: f32 = 10.0; +const PROJECTILE_Z_INDEX: f32 = 11.0; +const CURRENT_SHOT_Z_INDEX: f32 = 12.0; +const NEXT_SHOT_Z_INDEX: f32 = 12.0; + pub fn setup_cannon(mut commands: Commands, asset_server: Res) { let texture: Handle = asset_server.load("cannon/cannon.png"); @@ -186,8 +191,6 @@ pub fn detect_projectile_hit( slot_progress: target_progress, } }).remove::(); - // запоминаем индекс слота, куда попали - wave.last_insert_index = Some(insert_idx); } // Разблокировка (структурные изменения завершены) diff --git a/src/states/level/system_track.rs b/src/states/level/system_track.rs index 16dd292..68a4014 100644 --- a/src/states/level/system_track.rs +++ b/src/states/level/system_track.rs @@ -29,7 +29,7 @@ pub fn setup_track_with_buffer() -> TrackPath { TrackPath { points: full_points, - spawn_index: BUFFER_SLOTS-1, + spawn_index: BUFFER_SLOTS, buffer_size: BUFFER_SLOTS, } }