Перейти к содержимому

Уроки · 23

Точка плюс вектор

В уроке «Смещение» мы прибавляли одно число к одной координате, и точка сдвигалась в сторону. В уроке «Направление» появилась уже пара чисел сразу: direction_x * LENGTH и direction_y * LENGTH. Это та же самая идея смещения, только по двум координатам одновременно — такую пару чисел и называют вектором.

Сам по себе вектор не говорит, где что-то находится, — он говорит, на сколько сдвинуться: на столько-то по x, на столько-то по y. Пока его ни к чему не прибавили, у вектора нет положения на экране — только направление и длина.

// Вектор — это смещение: "на сколько", а не "где".
let vector_x = 30.0;
let vector_y = -10.0;

Чтобы получить настоящее место на экране, вектор нужно прибавить к уже известной точке:

// Точка + вектор = новая точка.
let point_x = center_x + vector_x;
let point_y = center_y + vector_y;

Это уже встречалось: center_x + direction_x * LENGTH в конце урока «Направление» — ровно то же сложение, точка (center_x) плюс вектор (direction_x * LENGTH), получающее точку, где заканчивается луч. Без него направление и длина так и остались бы подвешены в воздухе, без своего места на экране.

Точка и вектор — оба задаются парой чисел, x и y, и с точки зрения самих чисел это одно и то же: пара (30.0, -10.0) — и точка, и вектор сразу, смотря как на неё посмотреть. “Точка” и “вектор” — не два разных вида чисел, а два разных смысла для одной и той же пары.

Любую точку можно представить как вектор, который начинается в (0, 0) и заканчивается прямо в этой точке. Тогда координаты точки — это заодно и координаты вектора: они показывают, на сколько сдвинуться от (0, 0), чтобы туда попасть.

Отсюда и вычитание, которое уже встречалось в уроках «Расстояние» и «Направление»:

// mouse_x, mouse_y — точка курсора.
// center_x, center_y — точка центра.
// Курсор минус центр — вектор от центра к курсору.
let dx = mouse_x - center_x;
let dy = mouse_y - center_y;

Тут мы как будто переносим начало координат из (0, 0) в центр — и то, что от точки курсора осталось после вычитания, уже не место, а смещение: на сколько сдвинуться от центра, чтобы попасть в курсор. Складываем — получаем точку, вычитаем — получаем вектор.

Серая линия — вектор, нарисованный от левого верхнего угла: это он же, но как точка. Жёлтая линия — тот же самый вектор, только прибавленный к курсору (белая точка). Подвигай мышь и поменяй вектор полями ниже — оба конца двигаются одинаково, потому что это одни и те же два числа:

src/main.rs
use macroquad::prelude::*;
// Вектор один и тот же на каждом кадре, поэтому это константы
// (как в уроке «Константы»), а не переменные внутри loop.
const VECTOR_X: f32 = 150.0;
const VECTOR_Y: f32 = 100.0;
#[macroquad::main("Точка плюс вектор")]
async fn main() {
loop {
clear_background(BLACK);
// Тот же вектор, нарисованный от истинного (0, 0).
draw_line(0.0, 0.0, VECTOR_X, VECTOR_Y, 4.0, GRAY);
draw_circle(VECTOR_X, VECTOR_Y, 10.0, GRAY);
// Координаты курсора.
let (mouse_x, mouse_y) = mouse_position();
// Белая точка — сама позиция курсора, просто ориентир.
draw_circle(mouse_x, mouse_y, 6.0, WHITE);
// Тот же вектор, прибавленный к курсору: точка + вектор.
draw_line(mouse_x, mouse_y, mouse_x + VECTOR_X, mouse_y + VECTOR_Y, 4.0, YELLOW);
draw_circle(mouse_x + VECTOR_X, mouse_y + VECTOR_Y, 10.0, YELLOW);
next_frame().await;
}
}
  • vector_x, vector_y — смещение, пара чисел без собственного места на экране.
  • center_x + vector_x, center_y + vector_y — точка плюс вектор: результат — уже настоящая точка.
  • Приём один и тот же для любой точки и любого вектора — не только для центра и направления на курсор, но и для позиции игрока, врага, чего угодно.
  • Точка и вектор — не два разных типа значений, а два способа читать одну и ту же пару чисел: как место или как смещение.
  • Серая линия в демке — вектор от (0, 0), жёлтая — тот же вектор, прибавленный к курсору. Одинаковая длина и направление у обеих — потому что это одни и те же VECTOR_X, VECTOR_Y. В демке они — const вне main, как в уроке «Константы»: значение не зависит от кадра, так что пересчитывать его внутри loop незачем.
  • Если понадобится не просто прибавить вектор к точке, а растянуть его в несколько раз, саму точку не трогая, — это аккуратно разбирается в дополнительном уроке «Масштаб вокруг точки».