Уроки · 49
Точка и прямоугольник
В уроке «Пули пропадают за краем» у
inside_rectangle целых шесть параметров:
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}Уже тогда отметили: шесть — это точка (два числа) и прямоугольник (ещё четыре), просто разложенные по отдельности. Раз они всё равно всегда используются вместе, есть смысл завести под них свои типы — ту же идею мы уже применяли в уроке «Свои структуры».
Точка и прямоугольник как типы
Заголовок раздела «Точка и прямоугольник как типы»struct Point { x: f32, y: f32,}
struct Rect { x: f32, y: f32, width: f32, height: f32,}Назвал прямоугольник Rect, а не Rectangle — специально короче:
это по-прежнему означает «прямоугольник», просто сокращённо, чтобы не
путать с уже знакомым Rectangle из урока «Прямоугольные
кнопки». У того Rectangle есть ещё поле color,
для отрисовки, — а здесь нужна только сама геометрия: положение и
размер, без цвета.
Было шесть параметров, стало два
Заголовок раздела «Было шесть параметров, стало два»fn inside_rectangle(point: Point, rect: Rect) -> bool { point.x >= rect.x && point.x <= rect.x + rect.width && point.y >= rect.y && point.y <= rect.y + rect.height}Сама проверка не изменилась ни на символ — просто теперь x, y,
rect_x и остальные читаются через point. и rect.. Зато вызов
стал короче и понятнее. Было — как в уроке «Настоящий край
экрана»:
if inside_rectangle(bullet.x, bullet.y, 0.0, 0.0, screen_width(), screen_height()) {Стало:
let bullet_point = Point { x: bullet.x, y: bullet.y };let screen_rect = Rect { x: 0.0, y: 0.0, width: screen_width(), height: screen_height() };
if inside_rectangle(bullet_point, screen_rect) {Шесть чисел подряд — уже сложно на глаз понять, что где, особенно
если случайно переставить два соседних местами: компилятор такую
ошибку не заметит, это же просто f32 за f32. С Point и Rect
самих параметров всего два, и перепутать целую точку с целым
прямоугольником уже гораздо сложнее — они просто разного типа.
То же самое с distance и direction
Заголовок раздела «То же самое с distance и direction»distance раньше тоже принимала четыре отдельных числа — две точки,
разложенные по x и y, как в уроке «Радиус мышью»:
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()}Делаем с ней то же самое, что и с inside_rectangle выше, — вместо
четырёх чисел принимаем две Point:
fn distance(from: Point, to: Point) -> f32 { let dx = to.x - from.x; let dy = to.y - from.y; (dx * dx + dy * dy).sqrt()}С direction то же самое на входе: было четыре отдельных числа,
станет две Point. Но раньше она ещё и возвращала кортеж (f32, f32) (как в уроке «Свои функции») — теперь на
выходе тоже Point:
fn direction(from: Point, to: Point) -> Point { let dx = to.x - from.x; let dy = to.y - from.y; let distance = (dx * dx + dy * dy).sqrt();
if distance > 0.0 { Point { x: dx / distance, y: dy / distance } } else { Point { x: 1.0, y: 0.0 } }}Это не натяжка: в уроке «Точка плюс вектор» уже
разбирали, что точка и направление — одни и те же два числа, просто
с разным смыслом («место» или «движение»). Раз тип один и тот же,
логично и назвать его одним и тем же именем — Point тут означает
направление, а не место, но устроен ровно так же.
Что здесь происходит
Заголовок раздела «Что здесь происходит»struct Point { x, y }— пара чисел с именем, ровно то, что раньше было двумя отдельными параметрами почти в каждой функции.struct Rect { x, y, width, height }— то же самое для прямоугольника, но названо коротко и без поляcolor, чтобы не путать сRectangleиз урока «Прямоугольные кнопки».inside_rectangle,distance,direction— устройство внутри не поменялось, только вход и выход: было 6, 4 и 4 параметра, стало 2, 2 и 2, аdirectionещё и возвращаетPointвместо кортежа.- Меньше параметров — меньше мест, где значения можно перепутать
местами:
PointиRect— разные типы, и подсунуть одно вместо другого уже не выйдет так же незаметно, как с длинным списком голыхf32.