Останній приклад цього розділу поєднає разом код для круга та прямокутника. У нас є круг з позицією (cx, cy) і радіусом r та квадрат у положенні (rx, ry) з шириною/висотою (rw, rh).
Цей підхід визначення колізії буде складатися з двох послідовних дій. Спочатку ми перевіримо та дізнаємося, який край прямокутника ближче до круга, а потім за допомогою теореми Піфагора перевіримо, чи є зіткнення з цим ребром. Спочатку створимо тимчасові змінні для збереження найближчих X/Y значень країв квадрата. На початку ініціалізуємо їх значення початковим положенням центра круга:
let testX = cx;
let testY = cy;
Потім зробимо наступні перевірки:
Якщо круг ПРАВОРУЧ від квадрата, звіряємося з ПРАВИМ краєм квадрата.
Якщо круг ЛІВОРУЧ від квадрата, звіряємося з ЛІВИМ краєм квадрата.
Якщо круг НАД квадратом, звіряємося з ВЕРХНІМ краєм квадрата.
Якщо круг НИЖЧЕ квадрата, звіряємося з НИЖНІМ краєм квадрата.
Ось як це виглядає в коді з оператором if. Зверніть увагу на дещо інший if/else формат. Вам не потрібні фігурні дужки, якщо вам потрібно виконати лише оператор. Іноді це може здатися зручним і заощадливим способом, але будьте обережні, бо насправді ви не заощадите місце за рахунок читабельності коду, тому бажано так не робити!
if (cx < rx) testX = rx; // ліва сторона
else if (cx > rx + rw) testX = rx + rw; // права сторона
if (cy < ry) testY = ry; // верхня сторона
else if (cy > ry + rh) testY = ry + rh; // нижня сторона
Коли умови виконуються, то значення тестових змінних перезаписуються значеннями сторони квадрата. Якщо ж вищезазначені умови не виконуються, тоді значення тестових координат залишаються значеннями центру круга. Іноді одна координата матиме x або y значення якоїсь сторони квадрата, а інша x або y значення центру. Тобто у тестових значеннях будуть або значення якоїсь зі сторін квадрата або значення центру круга.
Щоб краще зрозуміти логіку і суть того, що тут відбувається, бажано знову взяти олівець і аркуш паперу та помалювати, щоб визначити які результати будуть при різних положеннях круга відносно квадрата. Тут ми по суті спочатку хочемо зрозуміти з якого боку від прямокутника знаходиться круг. Це своєю чергою допоможе визначити точку на цій стороні з якою ми й перевіримо наявність перетину з кругом. Кінець кінцем ми робимо вже знайому перевірку на колізію з точкою.
Тепер, коли ми знаємо, яке ребро квадрата потрібно перевіряти, ми запускаємо теорему Піфагора, використовуючи центр кола та значення координат, які ми знайшли вище:
const distX = cx - testX;
const distY = cy - testY;
const distance = sqrt((distX * distX) + (distY * distY));
Нарешті, ми порівняємо цю відстань з радіусом кола:
if (distance <= radius) {
return true;
}
return false;
Here's a full example:
Ось повний приклад:// змінні для положення та радіусу круга
let cx = 0;
let cy = 0;
let r = 30;
// змінні для положення та розмірів прямокутника
let sx;
let sy;
let sw = 200;
let sh = 200;
function setup() {
createCanvas(window.innerWidth, window.innerHeight);
noStroke();
// визначення положення координат для лівого верхнього кута, щоб квадрат був по центру полотна
sx = (width - sw) / 2;
sy = (height - sh) / 2;
}
function draw() {
background(255);
// оновлення координат рухомого круга координатами курсора
cx = mouseX;
cy = mouseY;
// результат перевірки на зіткнення
const isHit = isCircleWithRectCollides(cx, cy, r, sx, sy, sw, sh);
// при зіткненні змінюємо колір заливки
if (isHit) {
fill(255, 150, 0);
} else {
fill(0, 150, 255);
}
// малюємо квадрат
rect(sx, sy, sw, sh);
// малюємо круг
fill(0, 150);
ellipse(cx, cy, r * 2, r * 2);
}
// перевірка на перетин між кругом і прямокутником
function isCircleWithRectCollides(cx, cy, radius, rx, ry, rw, rh) {
// тестові змінні точки, з якою буде відбуватися перевірка на перетин
let testX = cx;
let testY = cy;
// які координати квадрата знаходяться найближче до круга?
if (cx < rx) {
testX = rx; // якщо круг лівіше прямокутника
} else if (cx > rx + rw) {
testX = rx + rw; // якщо круг правіше прямокутника
}
if (cy < ry) {
testY = ry; // якщо круг вище прямокутника
} else if (cy > ry + rh) {
testY = ry + rh; // якщо круг нижче прямокутника
}
// визначення відстані до найближчої точки ребра прямокутника, якщо круг за межами прямокутника
let distX = cx - testX;
let distY = cy - testY;
let distance = sqrt((distX * distX) + (distY * distY));
// якщо відстань менша за радіус круга це колізія!
if (distance <= radius) {
return true;
}
return false;
}
Цей приклад створено на основі коду Мета Вордена (дякую!).
До речі, оскільки ми вже маємо функцію на перевірку перетину кругу з точкою, то її можна повторно використати в кінці нашої функції:
// змінні для положення та радіусу круга
// перевірка на перетин між кругом і прямокутником
function isCircleWithRectCollides(cx, cy, radius, rx, ry, rw, rh) {
// тестові змінні точки, з якою буде відбуватися перевірка на перетин
let testX = cx;
let testY = cy;
// які координати квадрата знаходяться найближче до круга?
if (cx < rx) {
testX = rx; // якщо круг лівіше прямокутника
} else if (cx > rx + rw) {
testX = rx + rw; // якщо круг правіше прямокутника
}
if (cy < ry) {
testY = ry; // якщо круг вище прямокутника
} else if (cy > ry + rh) {
testY = ry + rh; // якщо круг нижче прямокутника
}
return isPointWithCircleCollides(testX, testY, cx, cy, radius);
}
У якості додаткової вправи ви можете намалювати точку тестових координат, що в результаті буде ковзати вздовж сторін квадрата або всередині нього і показувати вам позицію тої самої точки з якої відбувається перевірка на колізію з кругом. Якщо з такої програми прибрати малювання круга, то ви отримаєте свого роду точку, що завжди буде максимально наближеною до положення курсора, але ніколи не виходитиме за його межі. Також код з виявлення найближчих координат можна винести у окрему функцію, щоб використовувати її незалежно.
Далі: Завдання 2