До сих пор наши методы обнаружения столкновений основывались на математической основе. Хотя это полезно, есть случаи, когда математический подход просто не стоит, например, с неправильной, органической формой — требуемые вычисления слишком сложны и дороги, чтобы их оправдать. Вместо этого мы можем проверить каждый отдельный пиксель фигур. Это также дорогой подход, но он может быть, по крайней мере, оптимизирован.
Обнаружение столкновения
Это последний кусок, который мы попытаемся создать. Перетащите крючок на кокосовую пальму и обратите внимание, что написано в тексте внизу.
Шаг 1: Один за другим
Предположим, у нас есть два растровых изображения, и мы хотели бы проверить, сталкиваются ли они попиксельно: что это значит? Хорошо, давайте предположим, что оба ваших растровых изображения имеют размер 3x3px, и все пиксели заполнены.
Мы будем делать буквально это:
- Проверьте, если a1 и b1 находятся в одном месте.
- Повторите шаг (1), но теперь для a1 и b2.
- Повторите то же самое между a1 и b3, b4 … b9.
- Повторите шаги (1) — (3) для a2, a3 … a9.
Есть несколько замечаний, на которые я хотел бы обратить внимание.
наблюдение | Описание |
Верхние левые пиксели | Верхние левые пиксели для обоих растровых изображений используются в качестве начального пикселя для проверок. Например, a1 — это начальный пиксель, проверяемый по всем пикселям в b, который начинается с b1. Оба верхних левых пикселя. |
Строка сканирования | Как упоминалось в предыдущем пункте, проверка выполняется в порядке a1, a2, a3 … a9. Обратите внимание на расположение этих пикселей. |
Общее координатное пространство | Предположим, что обе графики добавлены в список отображения сцены. Расположение каждого пикселя в обоих растровых изображениях в координатном пространстве сцены будет сравниваться, чтобы увидеть, не происходит ли какое-либо перекрытие. |
Дорогое вычисление | Для двух растровых изображений 3×3 требуется максимум 9×9 повторений. Если мой размер растрового изображения увеличится до 100×100, вы сможете увидеть, насколько быстро растет общий расчет. Однако если какая-либо одна проверка возвращает положительный результат, то остальные проверки могут быть прерваны, поскольку, когда один пиксель перекрывается в обоих растровых изображениях, мы можем сказать, что между растровыми изображениями происходит конфликт |
Шаг 2: Дополнительные соображения
Теперь, Шаг 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 только в правом растровом изображении.
Шаг 3: Реализация ActionScript
В ActionScript мы можем наложить векторную графику на экземпляры BitmapData
. Вы можете представить, как ActionScript берет рентгеновский снимок векторной графики и передает его в BitmapData
, который действует как фотографическая пленка.
(Совет: если вы рисуете во Flash IDE, а затем экспортируете во FlashDevelop, как я это делаю, убедитесь, что размеры BitmapData
достаточно велики, чтобы содержать рисунок.)
Здесь CTree
и Hook
— два символа MovieClip, нарисованные во Flash; мы «рентген» их, чтобы получить экземпляр BitmapData для каждого:
частный вар кокос: CTree, hk: крюк; приватная переменная bdat1: BitmapData, bdat2: BitmapData; приватная переменная t1: TextField; публичная функция Matrix_Bitmap () { кокос = новая CTree (); AddChild (кокосовый орех); coconut.x = stage.stageWidth * 0,3; coconut.y = stage.stageHeight * 0,2; bdat1 = новые BitmapData (150, 150, true, 0x00000000); bdat1.draw (кокосовый орех); hk = новый крюк (); AddChild (кк); bdat2 = новые BitmapData (100, 50, true, 0x00000000); bdat2.draw (кк); hk.addEventListener (MouseEvent.MOUSE_DOWN, start); hk.addEventListener (MouseEvent.MOUSE_UP, end); t1 = новый TextField (); AddChild (t1); t1.x = stage.stageWidth * 0,2; t1.y = stage.stageHeight * 0,8; t1.width = 300; t1. высота = 100; stage.addEventListener (Event.ENTER_FRAME, проверка); }
Поэтому после этого мы начнем проверки с помощью hitTest()
класса BitmapData
.
На каждом проходящем кадре мы будем обновлять местоположение верхнего левого пикселя для каждого растрового изображения, прежде чем помещать экземпляры BitmapData
через эти строгие hitTest()
. Также обратите внимание, что диапазон для alpha
входа здесь составляет 0 ~ 255, то есть пороговое значение отсутствует. Подробнее о прозрачности на следующем шаге.
проверка приватной функции (e: Event): void { var point1: Point = новая точка (coconut.x, coconut.y); // верхний левый пиксель дерева var point2: Point = новая точка (hk.x, hk.y); // верхний левый пиксель крючка if (bdat1.hitTest (point1, 255, bdat2, point2, 255)) {// проверяем, перекрываются ли заполненные пиксели t1.text = "По крайней мере один пиксель столкнулся" } еще { t1.text = "Нет столкновения" } }
Вот пример вывода из ActionScript выше. Нажмите на крючок и поднесите его к кокосовой пальме и проверьте ответ в текстовом поле. Поэкспериментируйте с этим, подведя конец крючка к краю листьев кокосовой пальмы, чтобы увидеть, имеет ли это столкновение точность на уровне пикселей.
Шаг 4: Уровень прозрачности
Если у вас есть изображение, которое, например, постепенно исчезает (становится прозрачным), вы можете указать ActionScript, на каком уровне прозрачности вы считаете, что он подходит для выполнения проверки на столкновение.
Возьмите пример ниже: на спрайте есть несколько уровней прозрачности, и, как вы можете видеть, он постепенно понижается вправо. Если мы установим уровень прозрачности равным 0,5, то любой пиксель с альфа-значением 0,5 ~ 1 будет считаться непрозрачным и пригодным для обнаружения столкновений. Те, что ниже 0,5, будут считаться прозрачными. Даже когда эти пиксели сталкиваются с пикселями другого объекта, они не будут регистрировать истинное столкновение.
Еще одна деталь, которую я только что упомянул, заключается в том, что значение alpha
параметра функции hitTest в ActionScript BitmapData
действительности находится в диапазоне от 0 до 255. Поэтому я просто умножаю мое пороговое значение на 255, чтобы преобразовать диапазон.
проверка приватной функции (e: Event): void { var point1: Point = новая точка (bar1.x, bar1.y); var point2: Point = новая точка (bar2.x, bar2.y); порог вар: число = 255 * 0,5 if (bdat1.hitTest (точка1, порог, bdat2, точка2, порог)) { t1.text = "По крайней мере один пиксель столкнулся" } еще { t1.text = "Нет столкновения" } }
Шаг 5: Оптимизация
Я упомянул, что обнаружение столкновений на уровне пикселей требует больших вычислительных ресурсов. Это означает, что мы должны выбирать только тогда, когда это строго необходимо. Если два объекта находятся очень далеко друг от друга, то нет смысла использовать этот подход, и обычное обнаружение столкновения ограничивающего прямоугольника ( hitTestObject()
) подойдет.
Вот идея:
- Используйте
hitTestObject()
чтобы увидеть, столкнулись ли ограничивающиеhitTestObject()
двух объектов. - Если ответ да, то эти два объекта довольно близки. Продолжить проверку на уровне пикселей.
- Если ответ отрицательный, то эти два объекта находятся далеко друг от друга. Завершить проверку столкновений без проверки на уровне пикселей.
проверка приватной функции (e: Event): void { var closeEnough: Boolean = coconut.hitTestObject (hk) если (closeEnough) { var point1: Point = новая точка (coconut.x, coconut.y); var point2: Point = новая точка (hk.x, hk.y); if (bdat1.hitTest (point1, 255, bdat2, point2, 255)) { t1.text = "По крайней мере один пиксель столкнулся" } еще { t1.text = "Нет столкновения" } } }
Для полной ссылки на ActionScript, посмотрите Matrix_Bitmap3.as
из исходной загрузки .
Вывод
Спасибо за прочитанное. В следующем кратком совете мы будем использовать матрицы для преобразования BitmapData
.