Уроки · 51
Плавная погоня
В уроке «Погоня за мышью» кружок дёргается рядом с курсором: шаг там фиксированной длины, не зависит от расстояния, и на близкой дистанции кружок регулярно проскакивает мимо. Раз урок «Линейная интерполяция» уже пройден, дёргания можно убрать — причём без отдельного кода на торможение.
Идея: каждый кадр кружок сдвигается не на фиксированный шаг, а через
lerp — на factor от текущего расстояния до курсора:
position = lerp(position, mouse, factor); // шаг — доля factor от текущего расстоянияРаз шаг всегда доля от расстояния, а не фиксированное число пикселей, он сам собой получается большим вдалеке и маленьким вблизи — торможение не пишется отдельно, оно берётся из самой формулы.
Попробуй сам
Заголовок раздела «Попробуй сам»Води мышью по демке — кружок плавно подъезжает следом, замедляясь у
цели. Дёрни мышь резко в сторону — кружок тут же снова ускорится.
Поменяй factor ниже:
use macroquad::prelude::*;
// Точка — как в уроке «Точка и прямоугольник».struct Point { x: f32, y: f32,}
// Линейная интерполяция (lerp) — как в уроке «Линейная интерполяция».fn lerp(from: Point, to: Point, t: f32) -> Point { Point { x: from.x + (to.x - from.x) * t, y: from.y + (to.y - from.y) * t, }}
// factor одна и та же на каждом кадре, поэтому это константа (как в// уроке «Константы»), а не переменная внутри loop.const FACTOR: f32 = 0.08;
#[macroquad::main("Плавная погоня")]async fn main() { // Кружок стартует в центре экрана. mut и вне loop — позиция должна // помнить прошлый кадр, а не сбрасываться каждый раз. let mut position = Point { x: screen_width() / 2.0, y: screen_height() / 2.0 };
loop { clear_background(BLACK);
// Курсор — цель, к которой каждый кадр чуть-чуть приближаемся заново. let (mouse_x, mouse_y) = mouse_position(); let mouse = Point { x: mouse_x, y: mouse_y };
// Каждый кадр сдвигаемся на factor от текущего расстояния до // курсора: далеко от цели шаг большой, у цели — маленький. position = lerp(position, mouse, FACTOR);
draw_circle(position.x, position.y, 30.0, YELLOW);
next_frame().await; }}Что здесь происходит
Заголовок раздела «Что здесь происходит»struct Point { x, y }иlerp(from, to, t)— те же самые, что и в уроке «Линейная интерполяция».mouseсчитается заново каждый кадр — курсор снова цель, к которой едем, даже если он только что переместился.position = lerp(position, mouse, factor)— кружок проезжает долюfactorоставшегося расстояния. Например, приfactor = 0.08на каждом кадре разрыв сокращается на 8%, то есть остаётся 92% от того, что было — расстояние меньше, значит и следующий шаг меньше.- До курсора кружок никогда не доедет ровно — расстояние с каждым кадром лишь уменьшается, не обнуляется. Для демонстрации это не беда: разница становится незаметной за пару кадров.
- Резко отодвинь мышь — расстояние снова большое, значит и шаг снова большой: кружок тут же ускоряется в сторону новой цели, без всякого отдельного кода на ускорение.
factorв коде —const FACTOR, а не переменная внутриloop: значение одно и то же на каждом кадре, пока ты сам не подвинешь ползунок, поэтому это константа, как в уроке «Константы».