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

Уроки · 52

Вращение

Давай сделаем так, чтобы вектор крутился — его направление менялось по кругу, а длина оставалась прежней, не растягивалась и не сжималась. Как посчитать его x и y, чтобы получилось именно вращение, а не что попало?

Первое, что приходит в голову, — на каждом кадре понемногу прибавлять что-то к x и к y по отдельности. Не выйдет: стоит прибавить число к одной координате, и длина вектора сразу меняется — он растягивается или сжимается, а не поворачивается на месте. Чтобы длину вернуть на место, пришлось бы каждый раз заново нормировать вектор (делить на его длину, как в уроке «Направление»).

И даже это не спасает до конца. Если вектор смотрит строго вдоль оси x, прибавление к x вообще не меняет направление — вектор просто становится длиннее вдоль той же прямой, а не поворачивается. Если вместо этого прибавлять к y, направление и правда начнёт поворачиваться — но до 90° так и не дойдёт никогда: с каждым шагом угол приближается к 90° всё ближе, а чтобы дойти до него ровно, нужно было бы прибавить бесконечность, а бесконечность в коде не отрисуешь.

Должно быть другое правило — такое, что сразу даёт нужные x и y для вращения. И оно есть: у чисел в Rust уже готовы функции .cos() и .sin() (те самые синус и косинус, знакомые ещё со школы) — берём и вызываем:

let x = angle.cos();
let y = angle.sin();

Если angle — это угол в радианах (не привычные градусы), cos и sin дают ровно то, что нужно: x и y точки на окружности радиусом 1, повёрнутой на этот угол. Длина вектора всегда останется 1, какой угол ни возьми. Подробнее про радианы и про то, что здесь вообще происходит геометрически, можно почитать в дополнительных уроках «Синус и косинус» и «Радианы» — для самого вращения достаточно знать, что cos/sin работают именно так.

А дальше всё просто: если на каждом кадре прибавлять к angle одно и то же число, вектор будет равномерно вращаться — угол понемногу растёт, а cos/sin каждый раз дают чуть-чуть другое направление на той же самой окружности.

Как уже говорилось в уроке «Координаты», ось y на экране растёт вниз, а не вверх, как в школьной математике — поэтому рост angle через cos/sin крутит на экране по часовой стрелке, а не против, как было бы на бумаге.

(1, 0)

Вектор всегда начинается в нуле — его направление это (angle.cos(), angle.sin()). Кнопка ниже каждый кадр увеличивает angle, и вектор плавно крутится по кругу.

  • (angle.cos(), angle.sin()) — направление вектора: x и y точки на окружности радиусом 1, повёрнутой на angle.
  • Если angle растёт на одно и то же число каждый кадр, вектор равномерно вращается — длина не меняется, меняется только направление.
  • Из-за перевёрнутой оси y вращение на экране идёт по часовой стрелке, а не против.
  • Этот вектор всегда начинается в нуле. В следующем уроке, «Спутник», с его помощью сделаем кружок, который вращается вокруг другого.