Статьи

Обнаружение столкновений на уровне пикселей

До сих пор наши методы обнаружения столкновений основывались на математической основе. Хотя это полезно, есть случаи, когда математический подход просто не стоит, например, с неправильной, органической формой — требуемые вычисления слишком сложны и дороги, чтобы их оправдать. Вместо этого мы можем проверить каждый отдельный пиксель фигур. Это также дорогой подход, но он может быть, по крайней мере, оптимизирован.


Это последний кусок, который мы попытаемся создать. Перетащите крючок на кокосовую пальму и обратите внимание, что написано в тексте внизу.


Предположим, у нас есть два растровых изображения, и мы хотели бы проверить, сталкиваются ли они попиксельно: что это значит? Хорошо, давайте предположим, что оба ваших растровых изображения имеют размер 3x3px, и все пиксели заполнены.

Попиксельная проверка.

Мы будем делать буквально это:

  1. Проверьте, если a1 и b1 находятся в одном месте.
  2. Повторите шаг (1), но теперь для a1 и b2.
  3. Повторите то же самое между a1 и b3, b4 … b9.
  4. Повторите шаги (1) — (3) для a2, a3 … a9.

Есть несколько замечаний, на которые я хотел бы обратить внимание.

наблюдение Описание
Верхние левые пиксели Верхние левые пиксели для обоих растровых изображений используются в качестве начального пикселя для проверок. Например, a1 — это начальный пиксель, проверяемый по всем пикселям в b, который начинается с b1. Оба верхних левых пикселя.
Строка сканирования Как упоминалось в предыдущем пункте, проверка выполняется в порядке a1, a2, a3 … a9. Обратите внимание на расположение этих пикселей.
Общее координатное пространство Предположим, что обе графики добавлены в список отображения сцены. Расположение каждого пикселя в обоих растровых изображениях в координатном пространстве сцены будет сравниваться, чтобы увидеть, не происходит ли какое-либо перекрытие.
Дорогое вычисление Для двух растровых изображений 3×3 требуется максимум 9×9 повторений. Если мой размер растрового изображения увеличится до 100×100, вы сможете увидеть, насколько быстро растет общий расчет. Однако если какая-либо одна проверка возвращает положительный результат, то остальные проверки могут быть прерваны, поскольку, когда один пиксель перекрывается в обоих растровых изображениях, мы можем сказать, что между растровыми изображениями происходит конфликт

Теперь, Шаг 1 может быть взят буквально, если все пиксели заполнены. С помощью растровой графики мы определяем область прямоугольного измерения. Но не все пиксели заполнены для формирования графики.

В приведенном ниже примере показано правильное растровое изображение, занимающее только b2, b4, b5, b6 и b8. В этом случае мы должны проверить каждый пиксель в левом растровом изображении (a1, a2, a3 … a9) по отношению только к пикселям b2, b4, b5, b6, b8 в правом растровом изображении.

Не все пиксели заполнены.

Теперь ActionScript предоставляет нам еще один параметр, alpha , который определяет прозрачность пикселя, где 0 полностью прозрачен, а 1 полностью непрозрачен. Для b2, b4, b5, b6, b8 мы можем определить пороговое значение для alpha , скажем, 0,5.

Итак, предположим, что b2 и b8 оба пикселя с alpha 0,1; поскольку они меньше порогового значения 0,5, мы не будем считать их заполненными пикселями и поэтому не будем их проверять. Таким образом, в конце каждый пиксель в левом растровом изображении (a1, a2, a3 … a9) проверяется по b4, b5, b6 только в правом растровом изображении.


В ActionScript мы можем наложить векторную графику на экземпляры BitmapData . Вы можете представить, как ActionScript берет рентгеновский снимок векторной графики и передает его в BitmapData , который действует как фотографическая пленка.

(Совет: если вы рисуете во Flash IDE, а затем экспортируете во FlashDevelop, как я это делаю, убедитесь, что размеры BitmapData достаточно велики, чтобы содержать рисунок.)

Здесь CTree и Hook — два символа MovieClip, нарисованные во Flash; мы «рентген» их, чтобы получить экземпляр BitmapData для каждого:

Поэтому после этого мы начнем проверки с помощью hitTest() класса BitmapData .

На каждом проходящем кадре мы будем обновлять местоположение верхнего левого пикселя для каждого растрового изображения, прежде чем помещать экземпляры BitmapData через эти строгие hitTest() . Также обратите внимание, что диапазон для alpha входа здесь составляет 0 ~ 255, то есть пороговое значение отсутствует. Подробнее о прозрачности на следующем шаге.

Вот пример вывода из ActionScript выше. Нажмите на крючок и поднесите его к кокосовой пальме и проверьте ответ в текстовом поле. Поэкспериментируйте с этим, подведя конец крючка к краю листьев кокосовой пальмы, чтобы увидеть, имеет ли это столкновение точность на уровне пикселей.


Если у вас есть изображение, которое, например, постепенно исчезает (становится прозрачным), вы можете указать ActionScript, на каком уровне прозрачности вы считаете, что он подходит для выполнения проверки на столкновение.

Возьмите пример ниже: на спрайте есть несколько уровней прозрачности, и, как вы можете видеть, он постепенно понижается вправо. Если мы установим уровень прозрачности равным 0,5, то любой пиксель с альфа-значением 0,5 ~ 1 будет считаться непрозрачным и пригодным для обнаружения столкновений. Те, что ниже 0,5, будут считаться прозрачными. Даже когда эти пиксели сталкиваются с пикселями другого объекта, они не будут регистрировать истинное столкновение.

Уровень прозрачности.

Еще одна деталь, которую я только что упомянул, заключается в том, что значение alpha параметра функции hitTest в ActionScript BitmapData действительности находится в диапазоне от 0 до 255. Поэтому я просто умножаю мое пороговое значение на 255, чтобы преобразовать диапазон.


Я упомянул, что обнаружение столкновений на уровне пикселей требует больших вычислительных ресурсов. Это означает, что мы должны выбирать только тогда, когда это строго необходимо. Если два объекта находятся очень далеко друг от друга, то нет смысла использовать этот подход, и обычное обнаружение столкновения ограничивающего прямоугольника ( hitTestObject() ) подойдет.

Вот идея:

  1. Используйте hitTestObject() чтобы увидеть, столкнулись ли ограничивающие hitTestObject() двух объектов.
  2. Если ответ да, то эти два объекта довольно близки. Продолжить проверку на уровне пикселей.
  3. Если ответ отрицательный, то эти два объекта находятся далеко друг от друга. Завершить проверку столкновений без проверки на уровне пикселей.

Для полной ссылки на ActionScript, посмотрите Matrix_Bitmap3.as из исходной загрузки .


Спасибо за прочитанное. В следующем кратком совете мы будем использовать матрицы для преобразования BitmapData .