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

    В прошлой статье рассматривалась работа с ContactListener. Вот только примеры, которые я использовал, были не совсем верно выбраны. В Box2D есть намного более удобные средства для фильтрации столкновений, а именно – фильтры. О них и напишу в этот раз.
    Использование фильтров из Box2D в Libgdx

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



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

    Исходники

    Можете скачать исходники отсюда.
    Поддержать автора
    Поделиться публикацией

    Похожие публикации

    Комментарии 0

    Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

    Самое читаемое