Не могу понять, как работает бит-бит

Я пытаюсь использовать маски бит столкновения и связывать тестовые битные маски в Swift, я хочу, чтобы два объекта не сталкивались друг с другом, поэтому я делаю:

firstNode.physicsBody?.collisionBitMask = 0b01
secondNode?.collisionBitMask = 0b10

Так как SpriteKit выполняет операцию AND на этих двух числах, результат не должен быть 00, так как 10 & 01 = 00?

Итак, почему все равно происходят столкновения?

Спасибо.

Ответ 1

Это не работает обработка столкновений. Когда два тела находятся на пересечении, физический движок выполняет логический оператор AND между текущим телом collisionBitMask и другим телом categoryBitMask:

Когда два физических тела контактируют друг с другом, может произойти столкновение. Эта маска столкновения bodys сравнивается с другой категорией bodys маски, выполняя логическую операцию И. Если результат отличен от нуля значение, на это тело влияет столкновение. Каждый орган независимо выбирает, хочет ли он быть затронутым другим телом. Для Например, вы можете использовать это, чтобы избежать вычислений столкновений, которые делают незначительные изменения скорости bodys.

источник.

Таким образом, результат зависит от того, как вы устанавливаете categoryBitMask для этих двух тел. Значение по умолчанию для categoryBitMask равно 0xFFFFFFFF, означает, что все биты установлены. Поэтому, когда вы выполняете и между 0xFFFFFFFF и 0b10 или 0b01, результат будет отличным от нуля, поэтому столкновение.

Итак, например, установив ваши тела следующим образом:

spriteA.physicsBody?.categoryBitMask = 0b01
spriteA.physicsBody?.collisionBitMask = 0b01

и

spriteB.physicsBody?.categoryBitMask = 0b10
spriteB.physicsBody?.collisionBitMask = 0b10

даст вам результат, который вы хотите. Кроме того, это, вероятно, не точная настройка, которая вам нужна, это просто простой пример, и вам придется изменять значения в соответствии с вашими потребностями. В этом случае spriteA столкнется только с телами, у которых categoryBitMask установлено значение 0b01. То же самое касается spriteB, он столкнется с телами, у которых categoryBitMask установлено значение 0b10.

Кроме того, в случае, если вы не хотите, чтобы эти спрайты могли сталкиваться с чем-либо, просто установите для их свойств collisionBitMask значение 0.

Ответ 2

Это не то, как вы проверяете взаимодействие между узлами с битами столкновения.

  • CategoryBitMask - это категория объекта.
  • CollisionBitMask - это то, на что реагирует объект при столкновении.
  • ContactTestBitMask используется для уведомлений, когда пересечение происходит для указанной битовой маски.

Предположим, что у меня есть следующее:

struct PC {
    static var player: UInt32 = 0b10 //2
    static var enemy: UInt32 = 0b100 //4
    static var rock: UInt32 = 0b1000 //8
}

player.physicsBody!.categoryBitMask = PC.player
player.physicsBody!.collisionBitMask = PC.enemy | PC.rock
enemy.physicsBody!.categoryBitMask = PC.enemy
enemy.physicsBody!.collisionBitMask = PC.player

Итак, когда вы проверяете, происходит ли взаимодействие в функции didBeginContact, вы проверяете, произошло ли их взаимодействие с использованием битовой логики.

func didBeginContact(contact: SKPhysicsCountact) {
    //1
    let collision: UInt32 = contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask

    //2
    if collision == PC.player | PC.enemy {
        //An interaction occured between the player and enemy.
    }
  • Переменная collision использует побитовое ИЛИ, которое является |. В этом случае (если игрок касается врага), он получает категорию игрока (bodyA), которая равна 2, и получает категорию врага (bodyB), которая равна 4. Таким образом, 2 (0b10) OR 4 ( 0b100) равен 6 (0b110), которому присваивается столкновение.

  • Итак, тогда в выражении if он проверяет, является ли столкновение 6 равным (PC.player | PC.enemy), что верно, поэтому взаимодействие между игроком и противником, так как это было бы если 6 == 6.

Вы можете использовать переменную collision для проверки любого взаимодействия. Например, в моей тестовой игре у меня есть следующая функция, которая проверяет, какие объекты коснулись.

func didBeginContact(contact: SKPhysicsContact) {
    let collision: UInt32 = contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask

    //Collision between the penguin and land
    if collision == PhysicsCategory.Land | PhysicsCategory.Animal {
        lostLevel()
    } else if collision == PhysicsCategory.Animal | PhysicsCategory.Pillow {
        animalCounter -= 1
        if animalCounter == 0 {
            wonLevel()
        }
    }
}