Урок 7.7 · Интерфейсы и сайты с нуля · Модуль 7. Персонаж и движение · По подписке
Цель урока: Научиться проверять столкновение персонажа с предметом: подобрать монету, потерять здоровье на шипе и не сработать дважды.
Нужно знать заранее: Урок 7.5
Зачем это нужно: До сих пор сцена была пустой: герой ходил, и ничего не происходило. В игре интерес начинается там, где он с чем-то сталкивается — подбирает монету, наступает на шип, открывает дверь. Кажется, что за этим стоит физика, но в простом случае это одна проверка: пересеклись ли два прямоугольника.
Как это работает: У каждого объекта на сцене есть координата left и ширина width. Этого достаточно, чтобы понять, пересеклись ли они по горизонтали. Два отрезка — [aLeft, aLeft + aWidth] и [bLeft, bLeft + bWidth] — накладываются, если левый край первого левее правого края второго И правый край первого правее левого края второго: if (aLeft < bLeft + bWidth && aLeft + aWidth > bLeft) { /* столкнулись */ } Почему два условия, а не одно: если проверить только левый край, герой «соберёт» монету, ещё не дойдя до неё, а если только правый — пройдёт сквозь. Вместе они описывают наложение. Хитбокс. Прямоугольник, которым объект «касается» мира, называют хитбокс. Он не обязан совпадать с картинкой: у спрайта бывают прозрачные поля, у персонажа — длинный хвост или шляпа. В игре хитбокс обычно делают чуть меньше картинки, чтобы касание казалось честным: игрок видит, что «ещё чуть-чуть», и не считает игру сломанной. Наша геометрия. Сцена 256 px, герой 96 px, шаг 40 px. Монета стоит на left: 160px, шип — на left: 200px. Монета: герой дотягивается до неё, когда его правый край (x + 96) переходит за 160. Это происходит при x = 80: 80 + 96 = 176. Шип: 200 — значит касание начинается при x = 120: 120 + 96 = 216. Обратите внимание: точного совпадения «x равно 160» не будет никогда — шаг 40, а монета шириной 32. Сравнивать надо не позиции, а края. Один раз. После того как монета взята, а шип сработал, событие не должно повторяться на каждом шаге: иначе здоровье будет таять, пока герой стоит рядом. Для этого заводят флаг — переменную «уже случилось»: let coinTaken = false if (!coinTaken && overlaps(x, 96, 160, 32)) { coinTaken = true; /* ... */ } Флаг — такая же часть состояния игры, как x, score и health. Порядок. В обработчике кнопки сначала меняется координата, потом проверяются столкновения, потом сцена перерисовывается: x = x + 40 if (x > 160) { x = 160 } draw() checkCollisions() Если проверить до сдвига, событие опоздает на шаг: герой уже стоит на монете, а она ещё не взята.