Дополнительно · 6
Квадрат расстояния
В уроке «Радиус обнаружения» мы сравнивали расстояние с радиусом, а само расстояние считали с квадратным корнем, как в уроке «Расстояние». Оказывается, для такого сравнения корень можно не считать.
Корень можно не брать
Заголовок раздела «Корень можно не брать»Корень нам нужен, чтобы получить само расстояние в пикселях. Но когда мы только спрашиваем «ближе радиуса или дальше», настоящее число ни к чему. Достаточно сравнить квадраты.
Это работает потому, что возведение в квадрат не меняет, какое из двух
чисел больше, пока оба не отрицательные. Было 3 < 5, станет
9 < 25. А расстояние и радиус отрицательными не бывают.
Пример: dx равно 3, dy равно 4. С корнем расстояние получается 5, а
без корня 3 * 3 + 4 * 4 даёт 25. Возьмём радиус 6. Проверка
5 < 6 верна, и проверка 25 < 36 тоже верна. Ответ один и тот же.
// С корнем: считаем настоящее расстояние и сравниваем его с радиусом.(dx * dx + dy * dy).sqrt() < radius
// Без корня: сравниваем квадрат расстояния с квадратом радиуса.dx * dx + dy * dy < radius * radiusЗачем это нужно
Заголовок раздела «Зачем это нужно»Квадратный корень компьютер считает дольше, чем сложение и умножение. Одну проверку это не замедлит: Rust работает быстро, и в наших примерах разницы не заметить. Но если в игре тысячи объектов и каждый кадр для каждого нужна такая проверка, корни складываются во что-то заметное. Поэтому там, где проверок много, расстояния сравнивают в квадрате.
Переписывать так всё подряд не нужно: пока проверок мало, обычное расстояние проще читать.
Три ловушки
Заголовок раздела «Три ловушки»- Радиус тоже надо возвести в квадрат. Если сравнить квадрат расстояния с обычным радиусом, получится, что мы сравниваем «квадратные пиксели» с обычными, и ответ будет неверным.
- Для двух кругов, как в уроке
«Пересечение кружков», сравнивать
надо с
(r1 + r2) * (r1 + r2), а не сr1 * r1 + r2 * r2. Сумму радиусов возводим в квадрат целиком. - Если само расстояние нужно, например чтобы поделить на него, как в уроке «Направление», то корень всё равно нужен. Квадраты годятся только для вопроса «ближе или дальше».
Где ещё это работает
Заголовок раздела «Где ещё это работает»Поиск ближайшей цели из урока
«Поиск ближайшей цели» тоже можно делать без
корня: ближайшая по квадрату расстояния та же мишень, что и ближайшая по
самому расстоянию. Достаточно хранить в best_distance квадрат.
Попробуй сам
Заголовок раздела «Попробуй сам»Всё работает так же, как в уроке про радиус обнаружения: заведи белый кружок внутрь серого контура — турель покраснеет. Только теперь корня в коде нет. Меняй радиус ниже:
use macroquad::prelude::*;
// Радиус один и тот же на каждом кадре, поэтому это константа// (как в уроке «Константы»), а не переменная внутри loop.const RADIUS: f32 = 300.0;// Радиус в квадрате. Его тоже достаточно посчитать один раз.const RADIUS_SQUARED: f32 = RADIUS * RADIUS;
// Своя функция: квадрат расстояния между двумя точками. Это то, что в// уроке «Расстояние» стояло под корнем, только без самого корня.fn distance_squared(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}
#[macroquad::main("Квадрат расстояния")]async fn main() { loop { clear_background(BLACK);
// Центр экрана — здесь же стоит турель. let center_x = screen_width() / 2.0; let center_y = screen_height() / 2.0;
// Координаты курсора. let (mouse_x, mouse_y) = mouse_position();
// Контур — радиус обнаружения турели. draw_circle_lines(center_x, center_y, RADIUS, 3.0, GRAY);
// Турель красная, если игрок внутри радиуса, иначе синяя. Сравниваем // квадрат расстояния с квадратом радиуса — результат тот же. if distance_squared(center_x, center_y, mouse_x, mouse_y) < RADIUS_SQUARED { draw_circle(center_x, center_y, 40.0, RED); } else { draw_circle(center_x, center_y, 40.0, BLUE); }
// Игрок — кружок под курсором. draw_circle(mouse_x, mouse_y, 25.0, WHITE);
next_frame().await; }}Что здесь происходит
Заголовок раздела «Что здесь происходит»distance_squared(...)— своя функция, как в уроке «Свои функции»: считает квадрат расстояния, то есть то, что в уроке «Расстояние» стояло под корнем, но без самого корня.RADIUS_SQUARED— радиус в квадрате. Он, как и сам радиус, не меняется, поэтому достаточно посчитать его один раз, как константу.if distance_squared(...) < RADIUS_SQUAREDдаёт тот же ответ, что иif distance(...) < RADIUS, но корень не считается.- Корень нужен, когда нужно само расстояние. Для вопроса «ближе или дальше» хватает квадратов.