Уроки · 22
Направление
В уроке «Расстояние» dx и dy были не только строительным
материалом для формулы расстояния — вместе они ещё и показывают
направление от центра к курсору. Проблема в том, что размер этих чисел
зависит от того, как далеко мышь: dx и dy растут вместе с
расстоянием, хотя направление может быть тем же самым.
Если разделить dx и dy на distance — то есть на их же
собственную длину — получится пара чисел, которая показывает только
направление, а её длина всегда равна ровно 1, независимо от того, где
была мышь. Такое деление называют нормированием, а получившуюся
пару — нормированной: направление есть, а лишней длины уже нет.
// Делим каждую составляющую на длину — получаем направление длиной 1.let direction_x = dx / distance;let direction_y = dy / distance;Дальше это направление можно растянуть до любой нужной длины — умножение на число увеличивает длину ровно во столько же раз: умножил на 10 — длина стала в 10 раз больше. В этом и ценность единичного вектора: раз его собственная длина ровно 1, а единица, умноженная на любое число, даёт то же самое число, — умножив единичный вектор на 10, получаем вектор длиной ровно 10, а не просто “в 10 раз длиннее, чем было”.
Порядок вычитания важен
Заголовок раздела «Порядок вычитания важен»В уроке «Расстояние» было неважно, что из чего вычитать —
mouse_x - center_x или center_x - mouse_x дают одно и то же
расстояние, потому что оба числа потом возводятся в квадрат и минус
пропадает. А вот для направления порядок важен: dx = mouse_x - center_x — это направление от центра к мыши, а если вычесть в
обратную сторону, получится направление от мыши к центру, ровно
противоположное. Общее правило простое: из координат того, на что
смотрим, вычитаем координаты того, кто смотрит.
Попробуй сам
Заголовок раздела «Попробуй сам»Белая точка — неподвижный центр. Жёлтый луч из неё всегда смотрит на курсор, а вот его длина не зависит от того, далеко мышь или близко — она задаётся полем ниже:
use macroquad::prelude::*;
// Длина одна и та же на каждом кадре, поэтому это константа// (как в уроке «Константы»), а не переменная внутри loop.const LENGTH: f32 = 200.0;
#[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();
// Расстояние от центра до курсора (как в уроке «Расстояние»). let dx = mouse_x - center_x; let dy = mouse_y - center_y; let distance = (dx * dx + dy * dy).sqrt();
// Нормированное направление — та же пара чисел, но длиной ровно 1. let direction_x = dx / distance; let direction_y = dy / distance;
// Растягиваем направление до нужной длины. let end_x = center_x + direction_x * LENGTH; let end_y = center_y + direction_y * LENGTH;
// Белая точка — неподвижный центр. draw_circle(center_x, center_y, 10.0, WHITE); // Жёлтый луч — направление на курсор, заданной длины. draw_line(center_x, center_y, end_x, end_y, 4.0, YELLOW);
next_frame().await; }}Что здесь происходит
Заголовок раздела «Что здесь происходит»direction_xиdirection_y— направление на курсор, но уже без информации о расстоянии: длина этой пары всегда 1.direction_x * LENGTHиdirection_y * LENGTH— растягивают это направление до длиныLENGTH, какой бы она ни была.LENGTH— этоconstвнеmain, а не переменная внутриloop— как в уроке «Константы», её значение одно и то же на каждом кадре.center_x + ...иcenter_y + ...— сдвигают растянутое направление от центра, чтобы получить точку, где заканчивается луч (тот же приём сложения, что и в уроке «Смещение»).