score ui + cascade collapse

This commit is contained in:
nquidox 2026-04-12 00:28:37 +03:00
parent 8d673fb3aa
commit 0fd5719473
4 changed files with 81 additions and 17 deletions

View file

@ -12,3 +12,5 @@ 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;
pub const SCORE_Z_INDEX: f32 = 100.0;

View file

@ -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,
//сохранять порядок верхних трех
)
.chain(),
rotate_cannon,
move_projectiles,
//сохраняем порядок трех
//сохраняем порядок ниже
(
detect_projectile_hit,
check_and_remove_matches,
update_score_text,
move_queue_along_track,
)
.chain(),

View file

@ -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
// 🔥 КЛЮЧЕВОЕ: вся логика внутри проверки типов
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;
ball.slot_progress = 0.0; // "Примагничиваем" к новому слоту
}
}
// Сбрасываем прогресс ВСЕЙ очереди
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;
}
}

27
src/states/level/ui.rs Normal file
View file

@ -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<Score>,
mut query: Query<&mut Text2d, With<ScoreTextMarker>>,
) {
if score.is_changed() {
if let Ok(mut text) = query.single_mut() {
text.0 = format!("Score: {}", score.0);
}
}
}