diff --git a/src/states/level/constants.rs b/src/states/level/constants.rs index b108631..4a34b8b 100644 --- a/src/states/level/constants.rs +++ b/src/states/level/constants.rs @@ -11,4 +11,6 @@ pub const WARMUP_BALL_MOVEMENT_MULTIPLIER: f32 = 5.0; // во сколько р 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 +pub const NEXT_SHOT_Z_INDEX: f32 = 12.0; + +pub const SCORE_Z_INDEX: f32 = 100.0; \ No newline at end of file diff --git a/src/states/level/plugin.rs b/src/states/level/plugin.rs index 52e3f73..92a514e 100644 --- a/src/states/level/plugin.rs +++ b/src/states/level/plugin.rs @@ -8,7 +8,7 @@ impl Plugin for LevelPlugin { fn build(&self, app: &mut App) { app.add_systems( OnEnter(GameState), - (setup_level, initialize_queue, setup_cannon).chain(), + (setup_level, initialize_queue, setup_cannon, setup_score_ui).chain(), ) .add_systems( Update, @@ -18,17 +18,20 @@ impl Plugin for LevelPlugin { warmup_queue_movement, //до спавна остальных шариков spawn_new_ball, check_wave_completion, - //cannon systems - cycle_cannon_type, - update_cannon_preview, - spawn_projectile_from_cannon, - //сохранять порядок верхних трех + //сохраняем порядок систем пушки + ( + cycle_cannon_type, + update_cannon_preview, + spawn_projectile_from_cannon, + ) + .chain(), rotate_cannon, move_projectiles, - //сохраняем порядок трех + //сохраняем порядок ниже ( detect_projectile_hit, check_and_remove_matches, + update_score_text, move_queue_along_track, ) .chain(), diff --git a/src/states/level/system_ball.rs b/src/states/level/system_ball.rs index 07a280d..e507751 100644 --- a/src/states/level/system_ball.rs +++ b/src/states/level/system_ball.rs @@ -263,20 +263,52 @@ pub fn check_and_remove_matches( // --- СХЛОПЫВАНИЕ ОЧЕРЕДИ --- if has_left_neighbors && has_right_neighbors { - // 🔸 Удаление ВНУТРИ: сдвигаем все шарики СПРАВА влево - println!("Closing gap ({}..{}), shifting right balls left by {}", + // Находим ближайшего левого соседа (максимальный индекс среди тех, что левее удаляемых) + let left_neighbor_type = balls_sorted.iter() + .filter(|(_, b)| b.slot_index < removed_min_idx) + .max_by_key(|(_, b)| b.slot_index) + .map(|(_, b)| b.ball_type); + + // Находим ближайшего правого соседа (минимальный индекс среди тех, что правее удаляемых) + let right_neighbor_type = balls_sorted.iter() + .filter(|(_, b)| b.slot_index > removed_max_idx) + .min_by_key(|(_, b)| b.slot_index) + .map(|(_, b)| b.ball_type); + + println!("Closing gap ({}..{}), removed {} balls", 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; // "Примагничиваем" к новому слоту + // 🔥 КЛЮЧЕВОЕ: вся логика внутри проверки типов + if left_neighbor_type == right_neighbor_type { + // === ОДИНАКОВЫЕ ТИПЫ: полное схлопывание === + println!(" → Same type ({:?}): full collapse + reset", left_neighbor_type); + + // Сдвигаем индексы правых шариков влево + for (entity, mut ball) in balls.p1().iter_mut() { + if ball.slot_index > removed_max_idx { + ball.slot_index -= removed_count; + } } + // Сбрасываем прогресс ВСЕЙ очереди + for (entity, mut ball) in balls.p1().iter_mut() { + ball.slot_progress = 0.0; + } + + // записываем ласт хит, чтоб имитировать триггер каскадного уничтожения + wave.last_insert_index = Some(removed_min_idx - 1); + + println!(" → Cascade armed at idx {}", removed_min_idx - 1); + } else { + // === РАЗНЫЕ ТИПЫ: НИЧЕГО не делаем === + // Дыра остаётся, индексы и прогресс не трогаем + println!(" → Different types ({:?} vs {:?}): gap preserved", + left_neighbor_type, right_neighbor_type); } return; } - // 🔸 Удаление в НАЧАЛЕ или КОНЦЕ: индексы не меняем - // (опционально: можно сбросить progress у правых соседей для чёткости) + // 🔸 Удаление в НАЧАЛЕ или КОНЦЕ: сбрасываем прогресс всем + for (entity, mut ball) in balls.p1().iter_mut() { + ball.slot_progress = 0.0; + } } \ No newline at end of file diff --git a/src/states/level/ui.rs b/src/states/level/ui.rs new file mode 100644 index 0000000..6e400cf --- /dev/null +++ b/src/states/level/ui.rs @@ -0,0 +1,27 @@ +use bevy::prelude::*; +use crate::states::level::*; + +pub fn setup_score_ui( + mut commands: Commands, +){ + commands.spawn(( + ScoreTextMarker, + Text2d::new("Score: 0"), + TextFont { font_size: 48.0, ..default() }, + TextColor(Color::WHITE), + Transform::from_xyz(320.0, 300.0, SCORE_Z_INDEX), + Visibility::Visible, + LevelMarker, + )); +} + +pub fn update_score_text( + score: Res, + mut query: Query<&mut Text2d, With>, +) { + if score.is_changed() { + if let Ok(mut text) = query.single_mut() { + text.0 = format!("Score: {}", score.0); + } + } +} \ No newline at end of file