Уроки · 42
Круглые кнопки
Сделаем своё подобие кнопки — просто кружок на экране. Пока кружок никто не трогает, он своего обычного цвета. Как только на него нажали — красится в другой цвет. Отпустили — возвращается обратно.
Для этого нужны сразу две проверки: кнопка мыши зажата (уже знакомо по уроку «Клик мышью»), и мышь при этом находится внутри круга (та же геометрия, что и в уроке «Радиус обнаружения» — расстояние меньше радиуса). Кнопка считается нажатой, только если верно и то, и другое одновременно.
Логическое И
Заголовок раздела «Логическое И»В уроке «Тип bool» мы увидели, что любая проверка — это просто
bool. Знак && называется логическое И, и означает он ровно
то же самое слово «и» в обычной речи: «и то, и другое». Он берёт два
bool и отвечает на один вопрос — верно ли и первое, и
второе одновременно:
- И первое
true, и второеtrue→ результатtrue. - Если хотя бы одно из двух —
false, результат тожеfalse, сколько бы условий ни было верных из остальных.
let pressed = mouse_down && inside;Здесь это работает так: чтобы кнопка считалась нажатой, должны быть
верны сразу оба утверждения — и что кнопка мыши зажата прямо
сейчас (mouse_down), и что координаты мыши находятся внутри
круга (inside). Зажать мышь мимо кнопки — верно только первое,
pressed будет false. Навести мышь на кнопку, но не нажимать, —
верно только второе, pressed тоже false. Только когда оба условия
сходятся одновременно, pressed становится true — в этом и есть
логика знака &&, а не просто механическое «слепить два true в
один».
Замени содержимое src/main.rs на это:
use macroquad::prelude::*;
// Один кружок-кнопка: положение, радиус и обычный цвет.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() { loop { clear_background(BLACK);
let w = screen_width(); let h = screen_height();
// Четыре кнопки в ряд — у каждой своя доля ширины экрана и свой радиус. let buttons = [ Circle { x: w * 0.2, y: h * 0.5, radius: 140.0, color: YELLOW }, Circle { x: w * 0.4, y: h * 0.5, radius: 200.0, color: RED }, Circle { x: w * 0.6, y: h * 0.5, radius: 160.0, color: GREEN }, Circle { x: w * 0.8, y: h * 0.5, radius: 220.0, color: PURPLE }, ];
let (mouse_x, mouse_y) = mouse_position(); // Кнопка мыши зажата прямо сейчас. let mouse_down = is_mouse_button_down(MouseButton::Left);
for button in &buttons { // Мышь попадает внутрь именно этого кружка. let inside = distance(mouse_x, mouse_y, button.x, button.y) < button.radius; // Кнопка нажата, только если верно и то, и другое сразу. let pressed = mouse_down && inside;
if pressed { draw_circle(button.x, button.y, button.radius, BLUE); } else { draw_circle(button.x, button.y, button.radius, button.color); } }
next_frame().await; }}Запусти как обычно:
cargo runЗажми кнопку мыши над любым из четырёх кружков — он посинеет. Отпусти — вернётся к своему цвету. А если зажать кнопку мыши не над кружком — ничего не произойдёт: одной из двух проверок не хватает. Попробуй прямо здесь:
Что здесь происходит
Заголовок раздела «Что здесь происходит»w * 0.2,w * 0.4,w * 0.6,w * 0.8— доли ширины экрана, тот же приём, что и в уроках «Проценты» и «Доля от 0 до 1»: не абсолютные пиксели, а часть от целого, поэтому кнопки остаются на своих местах на любом экране.[Circle { ... }, ...]— фиксированный массив из четырёх кружков: их ровно четыре, известно заранее, и это не меняется, — тот самый случай, когда массив уместнееVec(как в уроке «Разноцветные кружки»).inside—bool, попадает ли мышь в конкретный кружок;mouse_down—bool, зажата ли кнопка мыши. Оба уже встречались по отдельности раньше.mouse_down && inside— оба должны бытьtrueодновременно, иначеpressedокажетсяfalse. Мышь может быть зажата где угодно на экране — кнопка среагирует, только если это ещё и внутри неё.for button in &buttonsпроверяет и рисует каждую кнопку одним и тем же кодом — не важно, что цвета у них разные.- Радиус у каждой кнопки тоже свой, не один общий на все четыре —
именно поэтому он хранится как поле
radiusвCircle, а не отдельной константой снаружи: у каждого значенияbuttonsон собственный.