Нам не нужны

сь пользоватьсяSpriteKit и я следую учебнику для столкновений. Я изо всех сил пытаюсь понять следующий код:

struct PhysicsCategory {
  static let None      : UInt32 = 0
  static let All       : UInt32 = UInt32.max
  static let Monster   : UInt32 = 0b1       // 1
  static let Projectile: UInt32 = 0b10      // 2
}

Почему мы назначаем эти вещи под названиемbitMaps и как они работают позже в коде ниже?

func didBegin(_ contact: SKPhysicsContact) {

    // 1
    var firstBody: SKPhysicsBody
    var secondBody: SKPhysicsBody
    if contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask {
        firstBody = contact.bodyA
        secondBody = contact.bodyB
    } else {
        firstBody = contact.bodyB
        secondBody = contact.bodyA
    }

    // 2
    if ((firstBody.categoryBitMask & PhysicsCategory.Monster != 0) &&
        (secondBody.categoryBitMask & PhysicsCategory.Projectile != 0)) {
        if let monster = firstBody.node as? SKSpriteNode, let
            projectile = secondBody.node as? SKSpriteNode {
            projectileDidCollideWithMonster(projectile: projectile, monster: monster)

Спасибо!

Ответы на вопрос(2)

используемые для описания элемента в двоичном формате.

так что представьте, у вас есть 8 способов что-то описать. (В спрайтеките у вас 32)

Мы можем поместить эти 8 элементов в один байт, так как 8 бит находятся в байте, что позволяет нам экономить место и быстрее выполнять операции.

Вот пример 8 описаний

Attackable 1 << 0  
Ranged     1 << 1  
Undead     1 << 2  
Magic      1 << 3  
Regenerate 1 << 4  
Burning    1 << 5  
Frozen     1 << 6  
Poison     1 << 7  

Теперь у меня есть лучник и хочу классифицировать его. Я хочу сказать, что он живой дружелюбный юнит

Я бы использовалcategoryBitmask классифицировать его:

archer.categoryBitmask = Ranged

Это будет представлено в 1 байте как

00000010
||||||||_ Attackable
|||||||_ Ranged
||||||_ Undead
|||||_ Magic
||||_ Regenerate
|||_ Burning
||_ Frozen
|_ Poison

Теперь давайте скажем, что его стрелы являются огненными стрелами, я бы классифицировал это так:

arrow.categoryBitmask = Burning

00100000
||||||||_ Attackable
|||||||_ Ranged
||||||_ Undead
|||||_ Magic
||||_ Regenerate
|||_ Burning
||_ Frozen
|_ Poison

и, наконец, у нас есть зомби, которого можно поразить и со временем восстановить.

zombie.categoryBitmask = Attackable + Undead + Regenerate

00010101
||||||||_ Attackable
|||||||_ Ranged
||||||_ Undead
|||||_ Magic
||||_ Regenerate
|||_ Burning
||_ Frozen
|_ Poison

Теперь я хочу, чтобы моя стрела только попалаAttackable спрайты (в данном случае зомби)

Я бы установилcontactTestBitmask сказать стрелке, что он может поразить

arrow.contactTestBitmask = Attackable 00000001

Теперь нам нужно проверить, когда стрелка попадает в зомби, это гдеdidBeginContact приходит в

какаяdidBeginContact будет делать, это проверитьcontactTestBitmask движущегося объекта вcategoryBitmask что он попадает с помощью операции AND, чтобы найти совпадение

В нашем случае

arrow.contactTestBitmask =  00000001
zombie.categoryMask      =  00010101 AND
                            --------
                            00000001

Поскольку наше значение> 0, контакт был успешным.

Это значит, что Бегинс уволен.

Теперь, когда мы находимся в didBegins, нам нужно определить, какое физическое тело является нашей стрелой, а какое физическое тело является нашим зомби.

вот где приходит следующее утверждение

func didBegin(_ contact: SKPhysicsContact) {

    // 1
    var firstBody: SKPhysicsBody
    var secondBody: SKPhysicsBody
    if contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask {
        firstBody = contact.bodyA
        secondBody = contact.bodyB
    } else {
        firstBody = contact.bodyB
        secondBody = contact.bodyA
}

Поскольку стрелка = 00100000 и зомби = 00010101, мы знаем, что зомби имеет меньшее значение, чем стрелка, поэтому в этом случае зомби <стрелка.

Мы назначаемfirstBody зомби, иsecondBody стрелять

Теперь нам нужно предоставить условие.

Мы хотим сказать, что если нежить попадает под обжигаемый объект, сделайте что-нибудь.

Так что в коде это будет

if (firstBody & Undead > 0) && (secondBody & Burning > 0)
{
//burn zombie
}

Но что, если стрела была ледяной стрелой? Мы не хотим вдаваться в это заявление.

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

if (firstBody & Undead > 0) && (secondBody & Frozen > 0)
{
//freeze zombie
}

То, что делают эти if, - это убедиться, что в теле включены определенные функции, а затем выполнить какое-то действие в ответ на них.

Чтобы узнать больше о том, как работают битовые маски, я бы исследовал, как создавать таблицы истинности. По сути, это то, к чему это сводится. Мы просто создаем несколько таблиц истинности и пытаемся выяснить, является ли утверждение истинным, и если оно истинно, выполнить действие.

 GizGazGo29 сент. 2017 г., 23:47
Вверху, когда вы приводите пример из 8 описаний, я не понимаю, что там происходит, например, что такое «1 << 7»?
 GizGazGo29 сент. 2017 г., 23:40
Однако, Attackable 1 << 0 Ranged 1 << 1 Undead 1 << 2 Magic 1 << 3 Regenerate 1 << 4 Burning 1 << 5 Frozen 1 << 6 Яд 1 << 7 <- что такое «1 < <7 "вещи и
 Knight0fDragon29 сент. 2017 г., 23:41
Что ты спрашиваешь?
 Knight0fDragon29 сент. 2017 г., 23:49
@GizGazGo Я разбил его для вас позже, это биты << означает бит сдвига, так что 1 << 1 означает, взять значение и сдвинуть его влево, так что в двоичном коде вы переходите от 0001 к 0010

Управление битовыми масками contactTest и collison для включения / отключения определенных контактов и коллизий.

Для этого примера мы будем использовать 4 тела и покажем только последние 8 бит битовых масок для простоты. 4 тела - это 3 узла SKSpriteNode (каждое с физическим телом) и граница:

let edge = frame.insetBy(dx: 0, dy: 0)
physicsBody = SKPhysicsBody(edgeLoopFrom: edge)

Обратите внимание, что физическое тело «ребра» - это физическое тело сцены, а не узел.

Мы определяем 4 уникальные категории

let purpleSquareCategory:   UInt32 = 1 << 0  // bitmask is ...00000001
let redCircleCategory:      UInt32 = 1 << 1  // bitmask is ...00000010
let blueSquareCategory:     UInt32 = 1 << 2  // bitmask is ...00000100
let edgeCategory:           UInt32 = 1 << 31  // bitmask is 10000...00000000

Каждому физическому телу присваиваются категории, к которым он принадлежит:

    //Assign our category bit masks to our physics bodies
    purpleSquare.physicsBody?.categoryBitMask = purpleSquareCategory
    redCircle.physicsBody?.categoryBitMask = redCircleCategory
    blueSquare.physicsBody?.categoryBitMask = blueSquareCategory
    physicsBody?.categoryBitMask = edgeCategory  // This is the edge for the scene itself

Если бит в collisionBitMask тела установлен в 1, то он сталкивается (отскакивает) от любого тела, у которого '1' находится в той же позиции в его категорииBitMask. Аналогично для contactTestBitMask.

Если не указано иное, все сталкивается со всем остальным, и контакты не генерируются (ваш код не будет уведомлен, когда что-либо связывается с чем-либо еще):

purpleSquare.physicsBody.collisonBitMask = 11111111111111111111111111111111 // 32 '1's.

Каждый бит в каждой позиции равен «1», поэтому по сравнению с любой другой категорией «BitMask» Sprite Kit найдет «1», поэтому произойдет столкновение. Если вы не хотите, чтобы это тело сталкивалось с определенной категорией, вам нужно будет установить правильный бит в collisonBitMask на «0»

и его contactTestbitMask устанавливается на все 0:

redCircle.physicsBody.contactTestBitMask = 00000000000000000000000000000000  // 32 '0's

То же, что и для collisionBitMask, за исключением обратного.

Контакты или столкновения между телами можно отключить (оставив существующий контакт или столкновение без изменений), используя:

nodeA.physicsBody?.collisionBitMask &= ~nodeB.category

Логически мы используем битовую маску коллизии AND для узла A с помощью обратной (логический оператор NOT, оператор ~) битовой маски категории nodeB, чтобы «отключить» битовую маску этого узла A. например, чтобы красный круг не сталкивался с фиолетовым квадратом:

redCircle.physicsBody?.collisionBitMask = redCircle.physicsBody?.collisionBitMask & ~purpleSquareCategory

который можно сократить до:

redCircle.physicsBody?.collisionBitMask &= ~purpleSquareCategory

Объяснение:

redCircle.physicsBody.collisonBitMask = 11111111111111111111111111111111
purpleSquareCategory  = 00000000000000000000000000000001
~purpleSquareCategory = 11111111111111111111111111111110 
11111111111111111111111111111111 & 11111111111111111111111111111110 = 11111111111111111111111111111110 

redCircle.physicsBody.collisonBitMask теперь равен 11111111111111111111111111111110 redCircle больше не сталкивается с телами с категорией .... 0001 (purpleSquare)

Вместо того, чтобы отключать отдельные биты в collsionsbitMask, вы можете установить его напрямую:

blueSquare.physicsBody?.collisionBitMask = (redCircleCategory | purpleSquareCategory)
i.e. blueSquare.physicsBody?.collisionBitMask = (....00000010 OR ....00000001)

который равенblueSquare.physicsBody?.collisionBitMask = ....00000011

BlueSquare будет сталкиваться только с телами с категорией или ..01 или ..10

Контакты или столкновения между двумя телами можно включить (не затрагивая существующие контакты или столкновения) в любой точке, используя:

redCircle.physicsBody?.contactTestBitMask |= purpleSquareCategory

Мы логически И redMirk bitMask с битовой маской категории purpleSquare, чтобы «включить» этот бит в bitMask redcircle. Это не затрагивает любые другие биты в bitMas от RedCircel.

Вы можете убедиться, что каждая фигура «отскакивает» от края экрана следующим образом:

// Make sure everything collides with the screen edge
enumerateChildNodes(withName: "//*") { node, _ in
    node.physicsBody?.collisionBitMask |= self.edgeCategory  //Add edgeCategory to the collision bit mask
}

Примечание:

Столкновения могут быть односторонними, то есть объект A может столкнуться (отскочить) от объекта B, в то время как объект B продолжает движение, как будто ничего не произошло. Если вы хотите, чтобы два объекта отскакивали друг от друга, им обоим нужно сказать, чтобы они сталкивались друг с другом:

blueSquare.physicsBody?.collisionBitMask = redCircleCategory
redcircle.physicsBody?.collisionBitMask = blueSquareCategory

Однако контакты не являются односторонними; если вы хотите знать, когда объект A коснулся (связался) объекта B, достаточно настроить обнаружение контакта на объекте A в отношении объекта B. Вам не нужно настраивать обнаружение контакта на объекте B для объекта A.

blueSquare.physicsBody?.contactTestBitMask = redCircleCategory

Нам не нужныredcircle.physicsBody?.contactTestBitMask= blueSquareCategory

Ваш ответ на вопрос