Уроки · 70
Пересечение кружков
В уроках «Радиус обнаружения», «Круглые кнопки»
и других проверка была одна и та же: distance(...) < radius
— расстояние от точки до центра круга меньше радиуса. Но точка — это,
по сути, круг нулевого размера. А что, если оба объекта — настоящие
круги, и у каждого свой радиус?
Сумма радиусов вместо одного
Заголовок раздела «Сумма радиусов вместо одного»Два круга пересекаются, если расстояние между их центрами меньше суммы их радиусов:
distance(a.x, a.y, b.x, b.y) < a.radius + b.radiusЕсли бы у b радиус был 0 (то есть b — просто точка), формула
превратилась бы ровно в старую: distance(...) < a.radius. Сумма
радиусов — это то же самое правило, просто для двух кругов вместо
круга и точки.
Метод вместо отдельной функции
Заголовок раздела «Метод вместо отдельной функции»Раз у нас уже есть struct Circle (как в уроке «Круглые
кнопки»), эту проверку удобно повесить на неё методом
— тем же приёмом impl, что и в уроке «Методы»:
impl Circle { fn intersects_with(&self, other: &Circle) -> bool { distance(self.x, self.y, other.x, other.y) < self.radius + other.radius }}Вызывается он так: a.intersects_with(&b) — читается почти как
обычное предложение.
Замени содержимое src/main.rs на это:
use macroquad::prelude::*;
// Один круг: положение и радиус.struct Circle { x: f32, y: f32, radius: f32,}
impl Circle { // Пересекается ли этот круг с другим — сумма радиусов против расстояния. fn intersects_with(&self, other: &Circle) -> bool { distance(self.x, self.y, other.x, other.y) < self.radius + other.radius }}
// Своя функция: расстояние между двумя точками, как в уроке «Расстояние».fn distance(from_x: f32, from_y: f32, to_x: f32, to_y: f32) -> f32 { let dx = to_x - from_x; let dy = to_y - from_y; (dx * dx + dy * dy).sqrt()}
#[macroquad::main("Пересечение кружков")]async fn main() { loop { clear_background(BLACK);
// Неподвижный круг — всегда в центре экрана. let still = Circle { x: screen_width() / 2.0, y: screen_height() / 2.0, radius: 120.0, };
// Круг, который ходит за мышью. let (mouse_x, mouse_y) = mouse_position(); let moving = Circle { x: mouse_x, y: mouse_y, radius: 80.0 };
// Цвет одинаковый у обоих — по умолчанию жёлтый, меняется на // красный, как только круги пересеклись. let mut color = YELLOW; if moving.intersects_with(&still) { color = RED; }
draw_circle(still.x, still.y, still.radius, color); draw_circle(moving.x, moving.y, moving.radius, color);
next_frame().await; }}Запусти как обычно:
cargo runВоди мышью вокруг неподвижного круга — оба жёлтые, пока не соприкоснутся, и становятся красными, как только пересекаются. Попробуй сам:
Что здесь происходит
Заголовок раздела «Что здесь происходит»distance(...) < radius_a + radius_b— то же сравнение расстояния, что уже было много раз, просто с суммой двух радиусов вместо одного.intersects_with— метод наCircle, а не отдельная функция:self— это тот круг, у которого метод вызвали,other— второй круг, переданный в скобках.&selfи&other: &Circle— оба берутся по ссылке, а не в собственность: методу достаточно посмотреть на координаты и радиус, забирать себе сами круги незачем.- Оба круга красятся одним и тем же
color— проверка одна на двоих, поэтому и результат у них общий.
Эта проверка пригодится в следующем уроке — там будет уже не просто «красный или жёлтый», а настоящее попадание: пуля заденет цель, и обе исчезнут.