HitBox — это чаще всего невидимая область или группа областей, которая помогает обнаруживать коснулся ли объект другого объекта, у которого тоже есть свой хитбокс.
В HTML страницах изначально нет понятие хитбокса у блоков, поэтому в этом посте мы сами получим и обработаем их с помощью JS.
Для чего нам нужны хитбоксы?
Чаще всего для каких-нибудь игрушек или же симуляция, где важно определить касания блоков.
1 пример: block1 коснулся block2 и произошло какое-нибудь действие.
2 пример: player стоял на block1, как только он отошел с него, сразу же упал
Почему мы не можем просто сравнить координаты?
Мы можем сравнить координаты X=left и Y=top, но наше условие будет выполняться только, если block1 идеально встанет на место block2, что будет выглядеть странно, да и если вы делается какую-нибудь игру/симуляцию, это будет неправильным решением
Универсальность и размер нашей функции
Наша функция JS будет работать со всеми блоками, если мы дадим доступ к ним.
Размер функции будет зависеть от кол-ва видов ваших блоков, но по стандарту она занимает не больше 30 строк кода
Все действия будут проходить через 2 цикла for():
1 цикл: Для определения углов блоков.
2 цикл: Определения касания блоков между собой.
Логика получения координат:
Допустим у нас есть 3 блока разного размера и разных цветов (красный, зеленый, синий) с начальными позициями:

У каждого блока есть координата X и Y, которые находятся в левом углу самого блока:

Но у блоков помимо координат, есть высота и ширина (height, width):

Прибавляя эти значения между собой, мы уже можем получить все нужные нам координаты: x1, x2, y1, y2.

Приступим к коду
Для начала в .html файле напишем базовый код и наш главный блок:
<body> <main class="mainBox"> </main> <script src="script.js"></script> <!-- Заранее подключаем скрипт --> </body>
Внутри mainBox засунем наши 3 блока и дадим им классы
<main class="mainBox"> <div class="block red"></div> <!-- Обращаться ко всем в JS будем через класс --> <div class="block green"></div> <div class="block blue"></div> </main>
Добавим кнопку, чтобы мы могли определять будущие хитбоксы по нажатию.
Сразу же даем класс и onclick:
<main class="mainBox"> <div class="block red"></div> <div class="block green"></div> <div class="block blue"></div> </main> <button class="btn" onclick="getHitboxTouchResult()">Проверить</button>
Переходим в CSS и даем следующие стили:
body { margin: 0; /* Чтобы по краям не было отступов */ background-color: rgb(60, 60, 60); /* Серый цвет приятнее глазу :D */ } .mainBox { position: relative; /* Чтобы блоки могли использовать left, top в род. блоке */ } .block { position: absolute; /* Возможность использования left, top */ } /* Размеры и цвета доч. блоко */ .red { background-color: rgba(255, 0, 0, 0.6); width: 200px; height: 200px; } .blue { background-color: rgb(0, 0, 255, 0.6); width: 250px; height: 250px; } .green { background-color: rgba(0, 255, 0, 0.6); width: 100px; height: 100px; } .btn { position: absolute; /* Крепим кнопку снизу справа */ right: 0; bottom: 0; width: 100px; /* Даем размер */ height: 40px; }
Получаем такой результат:

Все блоки слева сверху, давайте переместим их дав left, top параметры:
.red { background-color: rgba(255, 0, 0, 0.6); width: 200px; height: 200px; left: 920px; top: 320px; } .blue { background-color: rgb(0, 0, 255, 0.6); width: 250px; height: 250px; left: 690px; top: 190px; } .green { background-color: rgba(0, 255, 0, 0.6); width: 100px; height: 100px; left: 640px; top: 420px; }
Теперь они у нас в таком положении по центру страницы:

Переходим в JS и обозначаем нашу главную функцию определения хитбоксов:
function setHitboxesAndCheck() {}
В нее записываем получения всех доч. блоков через класс block:
blocks = document.querySelectorAll(".block")
Все блоки у нас, теперь определим их координаты:
for (var i = 0; i < Object.keys(blocks).length; i++) { // повторяем цикл пока i не достигнет количества всех блоков }
Определим координаты X:
for (var i = 0; i < Object.keys(blocks).length; i++) { // параметры offset могут записывать данные блока, в нашем случае мы используем offsetLeft и offsetWidth // за счет того, что blocks является массивом, мы можем каждому блоку присвоить переменные blocks[i].x1 = blocks[i].offsetLeft // первая точка X1 blocks[i].x2 = blocks[i].offsetLeft + blocks[i].offsetWidth // вторая точка X2 за счет прибавления ширины }
Не забываем про Y:
for (var i = 0; i < Object.keys(blocks).length; i++) { blocks[i].x1 = blocks[i].offsetLeft blocks[i].x2 = blocks[i].offsetLeft + blocks[i].offsetWidth blocks[i].y1 = blocks[i].offsetTop blocks[i].y2 = blocks[i].offsetTop + blocks[i].offsetHeight // тут уже прибавляем высоту }
Координаты наших 4 точек уже готовы, выглядят они так:

Проверяем касания наших точек
Для начала поймем как мы будем это делать.
Представим 2 блока, у которых есть свои точки:

Мы видим, что blocks[0].y2 находится в blocks[1].
Вначале будем проверять координаты X:
if (blocks[1].x1 <= blocks[0].x2) { // Если координата x1 второго блока меньше или равна координате x2 второго блока if (blocks[0].x2 >= blocks[1].x1) { // Если координата x1 первого блока больше или равна координате x2 второго блока // В этих условия мы проверяем блоки именно касаются друг друга или просто находятся рядом console.log(true) // Если условия верны и блоки касаются по горизонтали, то мы выводим true } }
Подключим циклы для проверок всех блоков:
for (var i = 0; i < Object.keys(blocks).length; i++) { for (var o = 0; o < Object.keys(blocks).length; o++) { // чтобы проверять блоки между собой if (i != o) { // даем условия, чтобы блоки не сравнивали свои же координаты if (blocks[i].x1 <= blocks[o].x2) { // наши условия if (blocks[i].x2 >= blocks[o].x1) { // заменяем цифры на переменные console.log(true) } } } } }
Создаем еще одну функцию к которой подключим кнопку:
function getHitboxTouchResult() { // onclick нашей кнопки setHitboxesAndCheck() }
Мы видим, что в консоли (F12) выводится true если они касаются по координате X.
Если мы подставим красный блоки ниже синего, в таком случае все равно будет выводится true, надо исправлять.
Для этого дадим еще пару условий по координатам:
if (blocks[i].x1 <= blocks[o].x2) { if (blocks[i].x2 >= blocks[o].x1) { if (blocks[i].y1 <= blocks[o].y1) { // тут тоже самое, но в первом условии проверяем левые верхние углы между собой if (blocks[i].y2 >= blocks[o].y1) { console.log(true) // выводим true } } } }
Теперь мы можем полностью определить хитбокс по горизонтали и вертикали.
Чуть изменим нашу функцию, чтобы мы могли использовать ее в сравнениях.
Заменим:
console.log(true)
На:
return true
Также заменим в функции кнопки, простой вызов на:
console.log(setHitboxesAndCheck())
Для использования нескольких видов блоков, нужно будет лишь их указывать в сравнениях.
Весь код:
HTML
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Hitboxes</title> <link rel="stylesheet" href="style.css"> </head> <body> <main class="mainBox"> <div class="block red"></div> <div class="block green"></div> <div class="block blue"></div> </main> <button class="btn" onclick="getHitboxTouchResult()">Check</button> <script src="script.js"></script> </body> </html>
CSS
body { margin: 0; background-color: rgb(60, 60, 60); } .mainBox { position: relative; } .block { position: absolute; } .red { background-color: rgba(255, 0, 0, 0.6); width: 200px; height: 200px; left: 920px; top: 320px; } .blue { background-color: rgb(0, 0, 255, 0.6); width: 250px; height: 250px; left: 690px; top: 190px; } .green { background-color: rgba(0, 255, 0, 0.6); width: 100px; height: 100px; left: 640px; top: 420px; display: none; } .btn { position: absolute; right: 0; bottom: 0; width: 100px; height: 40px; }
JS
function setHitboxesAndCheck() { blocks = document.querySelectorAll(".block") for (var i = 0; i < Object.keys(blocks).length; i++) { blocks[i].x1 = blocks[i].offsetLeft blocks[i].x2 = blocks[i].offsetLeft + blocks[i].offsetWidth blocks[i].y1 = blocks[i].offsetTop blocks[i].y2 = blocks[i].offsetTop + blocks[i].offsetHeight } for (var i = 0; i < Object.keys(blocks).length; i++) { for (var o = 0; o < Object.keys(blocks).length; o++) { if (i != o) { if (blocks[i].x1 <= blocks[o].x2) { if (blocks[i].x2 >= blocks[o].x1) { if(blocks[i].y1 <= blocks[o].y1) { if(blocks[i].y2 >= blocks[o].y1) { return true } } } } } } } } function getHitboxTouchResult() { console.log(setHitboxesAndCheck()) }
Спасибо за прочтение данного поста.
Буду благодарен, если посетите мой телеграм канал: https://t.me/blg_projects
