Использование фильтров из Box2D в Libgdx

от автора

В прошлой статье рассматривалась работа с 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. Теперь, если запустить игру, персонаж будет контактировать со всеми объектами кроме других персонажей.

Вы должны были обратить внимание на то, что индекс имеет отрицательное значение. Если индекс положителен — объекты всегда контактируют, если отрицателен — никогда не контактируют.

Исходники

Можете скачать исходники отсюда.

ссылка на оригинал статьи http://habrahabr.ru/post/163885/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *