Уроки · 35
Список кружков
В уроке «Сколько угодно кружков» число кружков задавалось полем — но код всё равно рисовал их сам, по формуле с равным шагом. А что, если каждый кружок должен появиться там, где сам решит игрок — например, в точке клика?
Одну точку клика хранить легко — это пара чисел (f32, f32), тот же
кортеж, что уже возвращала mouse_position() в уроке
«Координаты мыши». Но точек будет несколько,
причём сколько именно — заранее неизвестно: зависит от того, сколько
раз кликнет игрок. Нужна коллекция, которая умеет расти сама, пока
работает программа.
Vec — список, который растёт
Заголовок раздела «Vec — список, который растёт»Vec — это список, у которого нет фиксированной длины: он начинается
пустым и увеличивается по одному элементу, когда нужно. Начать пустой
список точек можно так:
let mut points: Vec<(f32, f32)> = Vec::new();Vec сам по себе не говорит, что именно он хранит — это нужно указать
отдельно, в угловых скобках сразу после имени: Vec<(f32, f32)>
значит «список, где каждый элемент — пара чисел». Без этого Rust не
знал бы, какого типа элементы туда класть.
Vec::new() создаёт пустой список. Записывается не через точку, как
.push чуть ниже, а через двойное двоеточие: new — это не
что-то, что делают с уже готовым списком, а то, что создаёт его с
нуля, поэтому и вызывается от самого типа Vec, а не от значения.
А добавить в него новую точку — методом .push:
points.push(mouse_position());Замени содержимое src/main.rs на это:
use macroquad::prelude::*;
#[macroquad::main("Список кружков")]async fn main() { // Список точек, куда кликнул игрок — сначала он пустой. let mut points: Vec<(f32, f32)> = Vec::new();
loop { clear_background(BLACK);
// Кнопка мыши только что нажата — запоминаем точку клика. if is_mouse_button_pressed(MouseButton::Left) { points.push(mouse_position()); }
// Рисуем кружок в каждой точке, которую запомнили. for &(x, y) in &points { draw_circle(x, y, 20.0, YELLOW); }
next_frame().await; }}Запусти как обычно:
cargo runКликай по экрану — в каждой точке остаётся кружок, а старые никуда не пропадают. Попробуй прямо здесь:
Что здесь происходит
Заголовок раздела «Что здесь происходит»Vec<(f32, f32)>— растущий список кортежей: каждый элемент — пара координат одного кружка.Vec::new()создаёт пустой список — в нём пока нет ни одной точки.let mut points— список обязательно мутабельный (как в уроке «Изменяемые переменные»):.pushдобавляет в него новый элемент, а значит, изменяет сам список. Безmutэто бы не скомпилировалось.points.push(mouse_position())добавляет в конец списка новую пару координат — ровно ту, что вернулаmouse_position()в момент клика.is_mouse_button_pressed— то же самое условие «кнопку только что нажали», что и в уроке «Турель стреляет»: срабатывает один раз на клик, а не на каждый кадр, пока кнопка зажата.for &(x, y) in &pointsпроходит по всем точкам списка, сколько бы их ни было, и на каждой раскладывает кортеж обратно вxиy— та же идея, что иlet (x, y) = mouse_position();, только теперь внутри цикла.&points— ссылка на список: одалживаем его, чтобы прочитать и нарисовать каждую точку, а не навсегда. Разберём это подробно в «Кружки исчезают» и «Владение и ссылки» — а пока достаточно знать: без&программа просто не собралась бы.loopвыполняет этот код заново каждый кадр, а забрать один и тот же список в собственность дважды нельзя.