count matching balls system

This commit is contained in:
nquidox 2026-04-21 00:28:52 +03:00
parent f6b5765b83
commit 745ed5cc54
3 changed files with 95 additions and 5 deletions

View file

@ -18,4 +18,10 @@ pub enum DebugToggle{
Track, Track,
Grid, Grid,
Laser, Laser,
} }
#[derive(Component, Copy, Clone)]
pub struct HitMarker;
#[derive(Component, Copy, Clone)]
pub struct ToRemoveMarker;

View file

@ -47,6 +47,7 @@ impl Plugin for LinearPlayPlugin {
calculate_projectile_hits, calculate_projectile_hits,
linear_move_projectiles, linear_move_projectiles,
insert_projectile_into_track, insert_projectile_into_track,
count_matching_balls,
).in_set(LinearUpdateSet::Track), ).in_set(LinearUpdateSet::Track),
) )
.add_systems(OnExit(LinearPlayState), cleanup); .add_systems(OnExit(LinearPlayState), cleanup);

View file

@ -48,20 +48,20 @@ pub fn move_round_balls(
for (mut transform, mut ball) in &mut balls { for (mut transform, mut ball) in &mut balls {
// сразу обновляем прогресс // сразу обновляем прогресс
ball.track_progress += track.speed_norm * time.delta_secs(); ball.track_progress += track.speed_norm * time.delta_secs();
// потом позиционируем визуал // потом позиционируем визуал
for seg in &track.segments { for seg in &track.segments {
if ball.track_progress >= seg.t_start && ball.track_progress < seg.t_end { 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 t_local = (ball.track_progress - seg.t_start) / (seg.t_end - seg.t_start);
let mut pos = Vec2::ZERO; let mut pos = Vec2::ZERO;
match seg.segment_type{ match seg.segment_type {
SegementType::Line {} => { SegementType::Line {} => {
pos = seg.start_pos + seg.direction * seg.length * t_local; pos = seg.start_pos + seg.direction * seg.length * t_local;
// transform.translation = pos.extend(ROUND_BALL_Z); // transform.translation = pos.extend(ROUND_BALL_Z);
} }
SegementType::Turn {} => { SegementType::Turn {} => {
let angle = seg.start_angle + FRAC_PI_2 * seg.sweep_sign * t_local; let angle = seg.start_angle + FRAC_PI_2 * seg.sweep_sign * t_local;
pos = seg.center + Vec2::from_angle(angle) * seg.radius; 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<HitMarker>>,
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::<HitMarker>();
// берем прогресс и тип шарика в точке попадания
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);
}
}
}