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

в 11:40, , рубрики: android, box2d, filter, game development, Gamedev, java, libgdx, Разработка под android, метки: , , , ,

В прошлой статье рассматривалась работа с 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

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js