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

Уроки · 38

Радиус мышью

По сути это те же самые ингредиенты, что уже встречались по отдельности: is_mouse_button_pressed/is_mouse_button_down из урока «Отрезок мышью» — там так же фиксируется первая точка по нажатию и тянется вторая, пока зажато, только рисуется сам отрезок, а не вычисленное по нему расстояние; и расстояние как радиус из урока «Расстояние» — только там радиус следовал за курсором всё время, без клика, а здесь по отпусканию кнопки застывает насовсем.

Нажатие запоминает точку, откуда растёт кружок — она же останется его центром:

if is_mouse_button_pressed(MouseButton::Left) {
drag_x = mouse_x;
drag_y = mouse_y;
}

Пока кнопка зажата, радиус — это расстояние от той точки до курсора прямо сейчас, тем же distance, что и в уроке «Расстояние»:

let radius = distance(drag_x, drag_y, mouse_x, mouse_y).max(5.0);

.max(5.0) не даёт радиусу стать меньше 5 пикселей — если отпустить кнопку сразу после нажатия, расстояние будет совсем крошечным или вовсе нулевым, и кружок иначе пропал бы из виду.

Пока кнопка зажата, кружок только показывается превью — рисуется заново каждый кадр, но никуда не сохраняется:

if is_mouse_button_down(MouseButton::Left) {
draw_circle(drag_x, drag_y, radius, YELLOW);
}

А в момент отпускания кнопки кружок сохраняется насовсем — ровно с тем радиусом, что получился к этому моменту, и со случайным цветом:

if is_mouse_button_released(MouseButton::Left) {
let color = COLORS[rand::gen_range(0, COLORS.len())];
circles.push(Circle { x: drag_x, y: drag_y, radius, color });
}

Замени содержимое src/main.rs на это:

src/main.rs
use macroquad::prelude::*;
// Фиксированный список цветов, из которого выбираем случайный.
const COLORS: [Color; 4] = [YELLOW, RED, GREEN, BLUE];
// Один кружок: положение, радиус и цвет вместе, под понятными именами.
struct Circle {
x: f32,
y: f32,
radius: f32,
color: Color,
}
// Своя функция: расстояние между двумя точками, как в уроке «Расстояние».
fn distance(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).sqrt()
}
#[macroquad::main("Радиус мышью")]
async fn main() {
// Список уже сохранённых кружков — сначала пустой.
let mut circles: Vec<Circle> = Vec::new();
// Точка, где начали тянуть радиус текущего кружка.
let mut drag_x = 0.0;
let mut drag_y = 0.0;
loop {
clear_background(BLACK);
// Координаты мыши прямо сейчас.
let (mouse_x, mouse_y) = mouse_position();
// Кнопка мыши только что нажата — запоминаем точку начала.
if is_mouse_button_pressed(MouseButton::Left) {
drag_x = mouse_x;
drag_y = mouse_y;
}
// Радиус не может быть меньше 5 — иначе кружок пропадёт из виду.
let radius = distance(drag_x, drag_y, mouse_x, mouse_y).max(5.0);
// Кнопка зажата — показываем, каким получится кружок.
if is_mouse_button_down(MouseButton::Left) {
draw_circle(drag_x, drag_y, radius, YELLOW);
}
// Кнопку только что отпустили — сохраняем готовый кружок.
if is_mouse_button_released(MouseButton::Left) {
let color = COLORS[rand::gen_range(0, COLORS.len())];
circles.push(Circle { x: drag_x, y: drag_y, radius, color });
}
// Рисуем все уже сохранённые кружки.
for circle in &circles {
draw_circle(circle.x, circle.y, circle.radius, circle.color);
}
next_frame().await;
}
}

Запусти как обычно:

Окно терминала
cargo run

Зажми кнопку мыши в любой точке и, не отпуская, потяни в сторону — радиус кружка растёт вслед за мышью. Отпусти — кружок сохранится со случайным цветом. Попробуй прямо здесь:

  • is_mouse_button_pressed ставит точку drag_x/drag_y один раз, в момент нажатия, — та же идея, что и у первой точки отрезка в уроке «Отрезок мышью».
  • distance(drag_x, drag_y, mouse_x, mouse_y) — расстояние от той точки до курсора прямо сейчас, тот же приём, что и в уроке «Расстояние», только там радиус не сохранялся, а просто всё время следовал за курсором.
  • .max(5.0) не даёт радиусу стать меньше 5 пикселей — при клике без протягивания расстояние было бы совсем маленьким или нулевым.
  • Пока кнопка зажата, кружок только превью — рисуется каждый кадр заново, но нигде не сохраняется, поэтому и пропадает, стоит передвинуть мышь.
  • is_mouse_button_released срабатывает один раз, в кадр отпускания — ровно тогда кружок с текущим radius и случайным цветом попадает в circles и остаётся на экране уже навсегда.