Уроки · 48
Настоящий край экрана
В уроке «Пули пропадают за краем» рамка обзора была специально меньше экрана — чтобы своими глазами увидеть, как пуля пропадает. Раз мы уже убедились, что это работает, для настоящей игры рамка не нужна вовсе: можно сравнивать прямо с экраном.
Экран — тоже прямоугольник
Заголовок раздела «Экран — тоже прямоугольник»inside_rectangle не изменилась ни на символ — как и раньше, она
проверяет точку против прямоугольника из x, y, ширины и высоты. А
сам экран — это просто ещё один прямоугольник, только особенный:
левый верхний угол у него всегда (0, 0) (как в уроке
«Координаты»), а ширина и высота — это
screen_width() и screen_height().
if inside_rectangle(bullet.x, bullet.y, 0.0, 0.0, screen_width(), screen_height()) { draw_circle(bullet.x, bullet.y, 8.0, YELLOW); kept_bullets.push(bullet);}Никакого margin, никакого draw_rectangle_lines — только сама
проверка. Пуля пропадает ровно тогда, когда должна: покидая
настоящий край экрана. Просто теперь этого не видно — а мы точно
знаем, что это происходит, потому что убедились в этом в прошлом
уроке, на увеличенной, заметной рамке.
Попробуй сам
Заголовок раздела «Попробуй сам»Кликай сколько угодно раз — пули летят и пропадают за краем экрана, теперь совсем без видимой рамки, ровно как в настоящей игре:
use macroquad::prelude::*;
// Скорость одна и та же на каждом кадре, поэтому это константа// (как в уроке «Константы»), а не переменная внутри loop.const SPEED: f32 = 10.0;
// Одна пуля: положение и зафиксированное направление полёта.struct Bullet { x: f32, y: f32, direction_x: f32, direction_y: f32,}
// Своя функция: по двум точкам считает направление от первой ко второй,// как в уроке «Свои функции».fn direction(from_x: f32, from_y: f32, to_x: f32, to_y: f32) -> (f32, f32) { let dx = to_x - from_x; let dy = to_y - from_y; let distance = (dx * dx + dy * dy).sqrt();
if distance > 0.0 { (dx / distance, dy / distance) } else { (1.0, 0.0) }}
// Своя функция: точка (x, y) внутри прямоугольника (rect_x, rect_y,// rect_width, rect_height)? Та же проверка, что и в уроке «Прямоугольные// кнопки».fn inside_rectangle(x: f32, y: f32, rect_x: f32, rect_y: f32, rect_width: f32, rect_height: f32) -> bool { x >= rect_x && x <= rect_x + rect_width && y >= rect_y && y <= rect_y + rect_height}
#[macroquad::main("Настоящий край экрана")]async fn main() { // Список пуль — сначала пустой. let mut bullets: Vec<Bullet> = Vec::new();
loop { clear_background(BLACK);
// Турель стоит в центре экрана. let center_x = screen_width() / 2.0; let center_y = screen_height() / 2.0;
// Координаты мыши. let (mouse_x, mouse_y) = mouse_position();
// Куда смотрит турель — направление от центра к мыши. let (direction_x, direction_y) = direction(center_x, center_y, mouse_x, mouse_y);
// Глазик — центр турели плюс направление, растянутое на 25 пикселей. let eye_x = center_x + direction_x * 25.0; let eye_y = center_y + direction_y * 25.0;
// Кнопка мыши только что нажата — добавляем новую пулю в список. if is_mouse_button_pressed(MouseButton::Left) { bullets.push(Bullet { x: eye_x, y: eye_y, direction_x, direction_y, }); }
// Тело турели. draw_circle(center_x, center_y, 40.0, BLUE); // Глазик — смотрит на мышь. draw_circle(eye_x, eye_y, 10.0, WHITE);
// Новый пустой список — создаётся заново на каждом кадре, специально // для пуль, которые стоит оставить. let mut kept_bullets: Vec<Bullet> = Vec::new(); // Забираем старый список bullets в собственность — второй раз им // воспользоваться уже не выйдет. for mut bullet in bullets { // Двигаем пулю в её направлении. bullet.x += bullet.direction_x * SPEED; bullet.y += bullet.direction_y * SPEED;
// Пуля ещё на экране — рисуем и переносим её в новый список. // Сам экран и есть прямоугольник: от (0, 0) до (screen_width(), // screen_height()). if inside_rectangle(bullet.x, bullet.y, 0.0, 0.0, screen_width(), screen_height()) { draw_circle(bullet.x, bullet.y, 8.0, YELLOW); kept_bullets.push(bullet); } // Иначе пуля просто никуда не переносится и пропадает вместе // со старым списком, когда цикл закончится. } // На следующий кадр bullets станет тем, что мы только что собрали. bullets = kept_bullets;
next_frame().await; }}Что здесь происходит
Заголовок раздела «Что здесь происходит»inside_rectangle(bullet.x, bullet.y, 0.0, 0.0, screen_width(), screen_height())— та же самая функция, что и в уроке «Пули пропадают за краем», просто вызванная с границами настоящего экрана вместо уменьшенной рамки.0.0, 0.0— левый верхний угол экрана, он же начало координат.screen_width(),screen_height()— ширина и высота экрана, вместоview_width/view_heightиз прошлого урока.- Список пуль по-прежнему пересобирается каждый кадр —
for mut bullet in bullets, новыйkept_bullets,bullets = kept_bulletsв конце — устройство не поменялось, поменялась только сама граница. - Пропажу пули теперь не видно — она происходит за пределами того, что вообще можно разглядеть на экране, и в этом и есть разница с прошлым уроком.