Уроки · 63
Зона обнаружения
В уроке «Радиус обнаружения» турель смотрела только на расстояние. В уроке «Сектор обнаружения» — только на угол, а сам сектор был неограничен по дальности, уходил за край экрана. На деле обычно нужно и то, и другое сразу: игрок обнаружен, если он и достаточно близко, и в пределах нужного направления.
Оба условия сразу
Заголовок раздела «Оба условия сразу»Ничего нового считать не нужно — просто соединяем уже готовые
проверки через &&, тем же способом, что и в уроке «Круглые
кнопки»:
let inside = distance < radius && relative <= sector_span;distance и radius — из урока «Радиус обнаружения»,
relative и sector_span — из урока «Сектор
обнаружения». Турель срабатывает, только когда
курсор проходит обе проверки одновременно.
Рисуем настоящий ограниченный клин
Заголовок раздела «Рисуем настоящий ограниченный клин»Раз сектор теперь ограничен дальностью, длинные лучи за край экрана
больше ни к чему — зону обнаружения можно нарисовать как она есть:
кусок круга радиусом radius. Как раз для этого в уроке
«Дуга» и разбирали draw_arc:
draw_arc( center_x, center_y, 60, radius, sector_start.to_degrees(), 3.0, sector_span.to_degrees(), GRAY,);Это единственное место во всём уроке, где нужен перевод в градусы —
draw_arc принимает только их, как и предупреждали в уроке
«Дуга», хотя весь остальной код здесь по-прежнему в
радианах.
Самой дуги мало — получится только изогнутый край клина, без боковых
сторон. Их дорисовываем двумя обычными draw_line, от центра до
каждого конца дуги, длиной ровно radius:
let start_x = center_x + sector_start.cos() * radius;let start_y = center_y + sector_start.sin() * radius;draw_line(center_x, center_y, start_x, start_y, 3.0, GRAY);
let end_x = center_x + sector_end.cos() * radius;let end_y = center_y + sector_end.sin() * radius;draw_line(center_x, center_y, end_x, end_y, 3.0, GRAY);Дуга и два прямых отрезка вместе — ровно контур зоны обнаружения, в
точности то, что проверяет inside.
Попробуй сам
Заголовок раздела «Попробуй сам»Турель красная, только когда курсор одновременно и ближе radius, и внутри сектора между start и end (оба в радианах). Контур зоны — дуга и два прямых
края. Подвигай поля:
use macroquad::prelude::*;use std::f32::consts::PI;
#[macroquad::main("Зона обнаружения")]async fn main() { loop { clear_background(BLACK);
let radius = 250.0; // Первый луч сектора — начало. let sector_start = 1.57; // Второй луч сектора — конец. От первого до второго — по // часовой стрелке. let sector_end = 3.14;
let center_x = screen_width() / 2.0; let center_y = screen_height() / 2.0;
let (mouse_x, mouse_y) = mouse_position(); let dx = mouse_x - center_x; let dy = mouse_y - center_y;
// Расстояние до курсора (как в уроке «Расстояние»). let distance = (dx * dx + dy * dy).sqrt(); // Угол вектора направления к курсору, в радианах (как в уроке «Угол вектора»). let mouse_angle = dy.atan2(dx);
// Сколько радиан по часовой стрелке от sector_start до // sector_end — весь сектор целиком (как в уроке «Сектор // обнаружения»). let sector_span = (sector_end - sector_start).rem_euclid(2.0 * PI); // Сколько радиан по часовой стрелке от sector_start до курсора. let relative = (mouse_angle - sector_start).rem_euclid(2.0 * PI);
// Турель замечает курсор, только если он и ближе radius, и // внутри сектора — оба условия сразу, как в «Круглых кнопках». let inside = distance < radius && relative <= sector_span;
// Дуга — единственное место, где нужны градусы: draw_arc из // урока «Дуга» принимает только их, хотя весь остальной код // здесь в радианах. draw_arc( center_x, center_y, 60, radius, sector_start.to_degrees(), 3.0, sector_span.to_degrees(), GRAY, );
// Два прямых края сектора — от центра до концов дуги, длиной // ровно radius, замыкают контур с боков. let start_x = center_x + sector_start.cos() * radius; let start_y = center_y + sector_start.sin() * radius; draw_line(center_x, center_y, start_x, start_y, 3.0, GRAY);
let end_x = center_x + sector_end.cos() * radius; let end_y = center_y + sector_end.sin() * radius; draw_line(center_x, center_y, end_x, end_y, 3.0, GRAY);
// Турель красная, если курсор внутри зоны, иначе синяя. if inside { draw_circle(center_x, center_y, 40.0, RED); } else { draw_circle(center_x, center_y, 40.0, BLUE); }
// Игрок — кружок под курсором. draw_circle(mouse_x, mouse_y, 25.0, WHITE);
next_frame().await; }}Что здесь происходит
Заголовок раздела «Что здесь происходит»inside = distance < radius && relative <= sector_span— турель срабатывает, только если курсор ближе радиуса и внутри сектора одновременно.draw_arc(...)рисует изогнутый край зоны — единственное место, где понадобился.to_degrees(), потому что сама функция работает только с градусами.- Два
draw_line— прямые края зоны, от центра до концов дуги, длинойradius: замыкают контур с боков. - Турель красная внутри зоны, синяя снаружи — та же идея, что и в уроках «Радиус обнаружения» и «Сектор обнаружения».