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

Уроки · 36

Разноцветные кружки

В уроке «Список кружков» мы научились работать с Vec — списком, который растёт сам, пока работает программа. Но набор цветов, из которых выбираем, никогда не меняется — он известен заранее, раз и навсегда. Заводить для него растущий Vec было бы избыточно: цвета никогда не добавляются и не убираются, а вся гибкость Vec тут просто не нужна. Гораздо проще — массив: список с длиной, зафиксированной раз и навсегда, прямо в типе.

const COLORS: [Color; 4] = [YELLOW, RED, GREEN, BLUE];

Тип массива, [Color; 4], похож на Vec<T> из прошлого урока — тоже говорит, какого типа элементы внутри, — только скобки квадратные, а не угловые, и, кроме типа элемента, через точку с запятой указано ещё и само количество: ровно 4, не больше и не меньше. Это число — часть типа, зашитая в код так же, как COUNT в уроке «Сколько угодно кружков»: оно не может увеличиться, пока программа работает.

Справа от = — уже готовое значение: те же квадратные скобки, но на этот раз в них перечислены сами элементы через запятую, [YELLOW, RED, GREEN, BLUE] — их ровно столько, сколько сказано в типе.

Color — тип, который у нас давно на виду: это тип значений вроде YELLOW и BLACK, просто раньше не было повода называть его по имени.

У массива есть метод .len() — он возвращает, сколько элементов внутри. Число 4 в типе [Color; 4] всё-таки пришлось написать руками — это часть объявления массива, тут никуда не деться. Но это единственное место, где оно встречается: .len() в остальном коде читает длину прямо из COLORS, а не хранит её отдельно, как хранил бы отдельный const COUNT. Добавишь пятый цвет — поправишь только [Color; 4] на [Color; 5], а .len() везде сам вернёт уже новое число, без правок где-либо ещё.

У каждого элемента массива есть свой номер по порядку, начиная с 0 — он называется индексом. Раньше rand::gen_range выбирал случайную координату на экране (в уроке «Случайная точка»). Здесь тот же gen_range выбирает случайный индекс — число от 0 до COLORS.len() - 1, тот же принцип «до, но не включая», что и в 0..COUNT из урока «Сколько угодно кружков»:

let index = rand::gen_range(0, COLORS.len());
let color = COLORS[index];

COLORS[index] — доступ к элементу массива по индексу: число в квадратных скобках после названия массива и есть номер элемента, который нужно взять. Здесь это ровно тот случайно выбранный цвет.

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

src/main.rs
use macroquad::prelude::*;
// Фиксированный список цветов, из которого выбираем случайный.
const COLORS: [Color; 4] = [YELLOW, RED, GREEN, BLUE];
#[macroquad::main("Разноцветные кружки")]
async fn main() {
// Список кружков: координаты клика и выбранный для него цвет.
let mut circles: Vec<(f32, f32, Color)> = Vec::new();
loop {
clear_background(BLACK);
// Кнопка мыши только что нажата — новый кружок со случайным цветом.
if is_mouse_button_pressed(MouseButton::Left) {
let (x, y) = mouse_position();
// Случайный индекс от 0 до длины списка COLORS.
let index = rand::gen_range(0, COLORS.len());
circles.push((x, y, COLORS[index]));
}
// Рисуем каждый кружок его собственным цветом.
for &(x, y, color) in &circles {
draw_circle(x, y, 20.0, color);
}
next_frame().await;
}
}

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

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

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

  • const COLORS: [Color; 4] = [...] — массив из четырёх цветов, собранных в одном месте, а не в четырёх отдельных переменных.
  • COLORS.len() — длина массива, 4, взятая из самого массива, а не прописанная отдельно.
  • rand::gen_range(0, COLORS.len()) возвращает случайный индекс от 0 до COLORS.len() - 1 — та же функция, что и раньше, просто диапазон теперь подобран под размер массива.
  • COLORS[index] — доступ к элементу массива по индексу, тот самый случайно выбранный цвет.
  • Vec<(f32, f32, Color)> — кортеж вырос до трёх элементов: теперь каждый кружок хранит ещё и свой цвет вместе с координатами.