В прошлой статье рассматривалась работа с ContactListener
. Вот только примеры, которые я использовал, были не совсем верно выбраны. В Box2D есть намного более удобные средства для фильтрации столкновений, а именно – фильтры. О них и напишу в этот раз.
Фильтры обрабатываются перед обработкой коллизий. То есть, если на уровне фильтров мы укажем, чтобы какие-то объекты не сталкивались, то в дальнейшем обработки коллизий между этими объектами не будет. В случае же с использование ContactListener
, не будут срабатывать его методы для таких объектов. Оптимизация на лицо. А теперь поподробнее рассмотрим.
Категории и маски
Категории и маски – самый мощный способ для фильтрования столкновений, но также и самым сложный (для новичков). Идея состоит в том, чтобы определить категорию для типов объектов, и использовать маски для фильтрования столкновений между этими типами объектов. Для начала определим категории.
// 0000000000000001 in binary
final public static short CATEGORY_PLAYER = 0x0001;
// 0000000000000010 in binary
final public static short CATEGORY_BALOOM = 0x0002;
// 0000000000000100 in binary
final public static short CATEGORY_RUNNER = 0x0004;
// 0000000000001000 in binary
final public static short CATEGORY_SCENERY = 0x0008;
Затем зададим их нашим объектам.
//игроку
f.categoryBits = MyWorld.CATEGORY_PLAYER;
//блокам и платформе
f.categoryBits = MyWorld.CATEGORY_SCENERY;
//для Baloom'а
f.categoryBits = MyWorld.CATEGORY_BALOOM;
//для Runner'а
f.categoryBits = MyWorld.CATEGORY_RUNNER;
Вы должны были заметить, что нумерация 0×001, 0×002, 0×004 и 0×008. Почему? Дело в том, что категории и маски – битовые поля (закодированы в 16 битах). Это означает, что возможные категории являются степенью 2 (в десятичной системе счисления: 1, 2, 4, 8, 16, 32, 64, 128 …, или в шестнадцатеричном: 0×1, 0×2, 0×4, 0×8, 0×10, 0×20, 0×40, 0×80 …). 16 битов означают, что есть 16 возможных категорий от 0×0001 до 0×8000.
Теперь определим маски.
final public static short MASK_PLAYER = CATEGORY_RUNNER | CATEGORY_SCENERY; // или ~MASK_PLAYER
final public static short MASK_BALOOM = CATEGORY_SCENERY ;
final public static short MASK_RUNNER = CATEGORY_PLAYER | CATEGORY_SCENERY ;
final public static short MASK_SCENERY = -1;
Обычная булева алгебра с типичными операциями над числами. Стоит лишь остановиться на маске и категории для пейзажных объектов. Почему -1? -1 означает, что объект будет контактировать со всеми другими объектами. Если же надо, чтобы объект не контактировал ни с кем, то установите значение 0.
Затем маски зададим нашим объектам.
//игроку
f.maskBits = MyWorld.MASK_PLAYER;
//блокам и платформе
f.maskBits = MyWorld.MASK_SCENERY;
//для Baloom'а
f.maskBits = MyWorld.MASK_BALOOM;
//для Runner'а
f.maskBits = MyWorld.MASK_RUNNER;
Если кто-то не понял, по маскам и категориям куски из кода представлены. Целиком назначения фильтра приведу на всякий случай, как пример для игрока:
Filter f = new Filter();
f.categoryBits = MyWorld.CATEGORY_PLAYER;
f.maskBits = MyWorld.MASK_PLAYER;
playerSensorFixture.setFilterData(f);
playerPhysicsFixture.setFilterData(f);
В итоге игрок будет взаимодействовать только с пейзажными объектами и с Runner’ом. Ballom только с пейзажем. Runner с игроком и пейзажем.
Фильтрация на уровне групп
Вы можете работать с категориями и масками, но порой нет необходимости их использовать, считать битовые маски и т.д. Группы специально были придуманы, чтобы отключить/включить обработку коллизий для каких-то связанных объектов.
Для начала, добавим ещё одного игрока.
BodyDef def2 = new BodyDef();
def.type = BodyType.DynamicBody;
Body boxP2 = world.createBody(def2);
player2 = new Player(boxP2);
player2.getBody().setTransform(5.0f, 1.0f, 0);
player2.getBody().setFixedRotation(true);
В классе Player
зададим группу.
Filter f = new Filter();
f.groupIndex = -1;
playerSensorFixture.setFilterData(f);
playerPhysicsFixture.setFilterData(f);
Так же необходимо задать группы для всех остальных объектов. Пускай для платформы groupIndex будет 3, а для блоков 2. В принципе, платформе и блокам можно группу не назначать, тогда будет установлено значение по умолчанию – 0. Теперь, если запустить игру, персонаж будет контактировать со всеми объектами кроме других персонажей.
Вы должны были обратить внимание на то, что индекс имеет отрицательное значение. Если индекс положителен — объекты всегда контактируют, если отрицателен — никогда не контактируют.
Исходники
Можете скачать исходники отсюда.
Автор: Suvitruf