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

Уроки · 39

Порядок отрисовки

Присмотрись к демке в уроке «Радиус мышью»: пока тянешь радиус, жёлтый превью-кружок рисуется под уже сохранёнными кружками. Но стоит отпустить кнопку — новый кружок оказывается поверх всех остальных. Это не случайность и не баг — так работает отрисовка в целом.

draw_circle и любая другая функция рисования — draw_rectangle, draw_line, draw_text — ведут себя как мазок кистью по холсту: закрашивают те пиксели, куда попадают, поверх всего, что там уже было нарисовано раньше. Экран — это не набор именованных фигур, которые помнят, кто где лежит, а просто изображение, которое каждый кадр рисуется заново, мазок за мазком, сверху вниз по коду.

Значит, то, что нарисовано позже, всегда оказывается видно сверху — независимо от того, где фигура находится на экране или в каком месте массива или списка лежит.

Чтобы по клику менять порядок рисования, нужно где-то хранить, какой он сейчас. Для значения, у которого всего два варианта — да или нет — в Rust есть тип bool, а сами варианты называются true и false:

let mut small_on_top = true;

Перевернуть такое значение на противоположное можно знаком ! перед ним: было true — станет false, и наоборот.

small_on_top = !small_on_top;

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

src/main.rs
use macroquad::prelude::*;
#[macroquad::main("Порядок отрисовки")]
async fn main() {
// Кто рисуется вторым — и поэтому окажется сверху.
let mut small_on_top = true;
loop {
clear_background(BLACK);
// Клик — меняем местами порядок отрисовки.
if is_mouse_button_pressed(MouseButton::Left) {
small_on_top = !small_on_top;
}
// Центр экрана — оба круга рисуются в одной точке.
let center_x = screen_width() / 2.0;
let center_y = screen_height() / 2.0;
if small_on_top {
// Большой круг первым, маленький вторым — маленький виден поверх.
draw_circle(center_x, center_y, 80.0, BLUE);
draw_circle(center_x, center_y, 35.0, YELLOW);
} else {
// Маленький круг первым, большой вторым — маленький скрыт под ним.
draw_circle(center_x, center_y, 35.0, YELLOW);
draw_circle(center_x, center_y, 80.0, BLUE);
}
next_frame().await;
}
}

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

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

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

  • is_mouse_button_pressed(...) тоже возвращает bool — мы просто никогда раньше не сохраняли такое значение в свою переменную, только сразу проверяли в if.
  • Клик переворачивает small_on_top через ! и сразу присваивает обратно в неё же — тем самым меняя местами два вызова draw_circle внутри if.
  • Круги остаются на тех же местах с теми же радиусами весь урок — меняется только порядок двух строк кода, и этого достаточно, чтобы поменять, кто кого закрывает.
  • В уроке «Свои структуры» то же самое происходило неявно: for circle in &circles рисует кружки в том порядке, в котором они лежат в Vec — то есть в порядке, в каком были добавлены через .push. Последний добавленный рисуется последним, а значит — оказывается сверху.