diff --git a/src/states/linear/components.rs b/src/states/linear/components.rs index 06548c8..2d78beb 100644 --- a/src/states/linear/components.rs +++ b/src/states/linear/components.rs @@ -18,4 +18,10 @@ pub enum DebugToggle{ Track, Grid, Laser, -} \ No newline at end of file +} + +#[derive(Component, Copy, Clone)] +pub struct HitMarker; + +#[derive(Component, Copy, Clone)] +pub struct ToRemoveMarker; \ No newline at end of file diff --git a/src/states/linear/plugin.rs b/src/states/linear/plugin.rs index 5c0ceac..5d39da1 100644 --- a/src/states/linear/plugin.rs +++ b/src/states/linear/plugin.rs @@ -47,6 +47,7 @@ impl Plugin for LinearPlayPlugin { calculate_projectile_hits, linear_move_projectiles, insert_projectile_into_track, + count_matching_balls, ).in_set(LinearUpdateSet::Track), ) .add_systems(OnExit(LinearPlayState), cleanup); diff --git a/src/states/linear/system_ball.rs b/src/states/linear/system_ball.rs index be907ed..24866bf 100644 --- a/src/states/linear/system_ball.rs +++ b/src/states/linear/system_ball.rs @@ -48,20 +48,20 @@ pub fn move_round_balls( for (mut transform, mut ball) in &mut balls { // сразу обновляем прогресс ball.track_progress += track.speed_norm * time.delta_secs(); - + // потом позиционируем визуал for seg in &track.segments { if ball.track_progress >= seg.t_start && ball.track_progress < seg.t_end { // вычисляем локальное нормализованое положение на треке let t_local = (ball.track_progress - seg.t_start) / (seg.t_end - seg.t_start); - + let mut pos = Vec2::ZERO; - match seg.segment_type{ + match seg.segment_type { SegementType::Line {} => { pos = seg.start_pos + seg.direction * seg.length * t_local; // transform.translation = pos.extend(ROUND_BALL_Z); } - + SegementType::Turn {} => { let angle = seg.start_angle + FRAC_PI_2 * seg.sweep_sign * t_local; pos = seg.center + Vec2::from_angle(angle) * seg.radius; @@ -72,3 +72,86 @@ pub fn move_round_balls( } } } + +pub fn count_matching_balls( + mut commands: Commands, + start_point: Query<(Entity, &RoundBall), With>, + balls: Query<(Entity, &RoundBall)>, +) { + // если хит маркеров нет, сразу выходим + if start_point.is_empty() { + return; + } + + println!("Проверка на группу начата"); + + //собираем все шарики на треке + let mut balls_sorted: Vec<(Entity, RoundBall)> = balls.iter().map(|(e, b)| (e, *b)).collect(); + + if balls_sorted.is_empty() { + return; + } + + // сортируем по прогрессу + balls_sorted.sort_by(|a, b| a.1.track_progress.total_cmp(&b.1.track_progress)); + + // принимаем шарик снаряд как точку отсчета + for (start_entity, start_round) in start_point.iter() { + // сразу снимаем маркер попадания с бывшего шарика-снаряда, который был встроен в трек + commands.entity(start_entity).remove::(); + + // берем прогресс и тип шарика в точке попадания + let start_progress = start_round.track_progress; + let hit_ball_type = start_round.ball_type; + + // будем итерировать по индексам + let mut hit_index = 0; + for (index, ball) in balls_sorted.iter().enumerate() { + if ball.1.track_progress == start_progress { + hit_index = index; + } + } + + let mut left_threshold = hit_index; + let mut right_threshold = hit_index; + + // ищем крайнего соседа слева + for li in (0..=hit_index).rev() { + // + if balls_sorted[li].1.ball_type == hit_ball_type { + // записываем индекс как порог + left_threshold = li; + continue; + } else { + // иначе прерываем + break; + } + } + + // то же самое для правого + for ri in hit_index..=balls_sorted.len() { + if balls_sorted[ri].1.ball_type == hit_ball_type { + right_threshold = ri; + continue; + } else { + break; + } + } + + // считаем размер группы + let group_size = right_threshold - left_threshold + 1; + if group_size < 3 { + continue; // не return, так как может быть несколько хит маркеров + } + + println!("Группа из 3+ шариков! Размер: {}", group_size); + + // маркируем группу по порогам на удаление + for entity in balls_sorted[left_threshold..=right_threshold] + .iter() + .map(|(e, _)| *e) + { + commands.entity(entity).insert(ToRemoveMarker); + } + } +}