Если у вас есть два узла, участвующих в столкновении, как описано в ответе @Luca Angeletti, вы можете превратить их в индекс различными способами.
- Если вы сделали каждый тип узла специализированный подкласс, и у вас есть соответствующие индексы, хранящиеся в качестве членов класса, затем вы можете преобразовать в соответствующий класс и посмотреть на поля индекса, например,
if let block = nodeA as? BlockNode, let ball = nodeB as? BallNode {
print("block \(block.blockIndex) hit ball \(ball.ballIndex)")
}
Узлы могут быть хэшируемыми, поэтому у вас могут быть словари для сопоставления их с индексами:
if let blockIndex = blockIndexes[nodeA], let ballIndex = ballIndexes[nodeB] {
print("block \(blockIndex) hit ball \(ballIndex)")
}
Вы можете использовать свойство userData
узлов для хранения всего, что вам нравится, включая индексы. Хотя шутить над NS-вещами становится некрасиво. https://developer.apple.com/documentation/spritekit/sknode/1483121-userdata
Вы можете выполнять линейное сканирование каждого массива.
if let blockIndex = blocks.firstIndex(of: nodeA), let ballIndex = balls.firstIndex(of: nodeB) {
print("block \(blockIndex) hit ball \(ballIndex)")
}
По вашему вопросу похоже, что у вас может быть отдельная битовая маска категории для каждого отдельного блока и каждого отдельного шара. Или, если вы этого не сделаете, это возможно, если их максимум 16. В любом случае, если это так, то вы можете сделать несколько щелчков по битам, чтобы взять categoryBitMask из физических тел, сдвинуть шар / блок на 16 бит (в зависимости от того, какое из старших битов будет сдвинуто), а затем взять log2 бита. маски, чтобы получить ваши индексы. Вы можете найти различные методы стука по битам для log2 здесь:
https://graphics.stanford.edu/~seander/bithacks.html#IntegerLogObvious Учитывая 16 вещей каждого типа, я бы сказал, просто сделайте # 4. Если у вас уже есть узлы подкласса, # 1 подойдет. Номер 2 немного расширяется, так что я не такой фанат этого. Номер 3 я бы не очень рекомендовал из-за материала NS. Номер 5 слишком хорош для своего блага.
Редактировать: Теперь, когда я снова читаю, звучит так, как будто у вас есть отдельные идентификаторы для категорий 1 ... 16, так что ваши битовые маски категории блоков похожи : blockCategoryMask | ID1
, blockCategoryMask | ID2
, et c. Это также может работать (в основном вариант № 5). Если вы идете по этому маршруту, вы можете просто вставить индекс непосредственно в маски категории:
let blockCategoryMask = UInt32(1<<4)
let ballCategoryMask = UInt32(1<<5)
Тогда физическое тело для блока получит маску blockCategoryMask | UInt32(index)
, и аналогично для мяч. В этом случае извлечение индекса составляет всего categoryBitMask & UInt32(0xf)
. Или, если вы поместите категории блоков и шаров в биты 0 и 1, а индексы в биты 2-5, то сдвиньте вправо на 2, чтобы получить индекс.
Отредактируйте в ответ на комментарий: ОК, так что давайте возьмем случай 6 различных категорий объектов, и каждый объект может попасть в одну из 16 различных подкатегорий. Чтобы иметь возможность контролировать, о каких контактах сообщается, необходимо назначить битовую маску для каждой из 6 основных категорий:
enum Category: UInt32 {
// Basic categories
case block = 0b000001
case ball = 0b000010
case shot = 0b000100
case obstacle = 0b001000
case wizard = 0b010000
case food = 0b100000
}
Поскольку вы использовали 6 бит для основной категории, у вас есть 26 бит осталось. Для кодирования 16 подкатегорий необходимо 4 бита. Вы можете поместить их в битовую маску категории над основными 6 битами. Примеры манипуляций:
func encodeObject(category: Category, subcategory: Int) -> UInt32 {
return category.rawValue | (UInt32(subcategory) << 6)
}
func nodeIsA(node: SKNode, category: Category) -> Bool {
guard let body = node.physicsBody else { return false }
return (body.categoryBitMask & category.rawValue) != 0
}
func subcategory(node: SKNode) -> Int {
guard let body = node.physicsBody else { fatalError("missing physicsbody") }
return Int(body.categoryBitMask >> 6)
}
Обратите внимание, что подкатегории являются всего лишь меткой для поездки; все ваши contactBitMasks будут иметь дело только с основными категориями.
По сути, вы используете тот факт, что у вас есть некоторые дополнительные биты в битовых масках категории тела тела для хранения случайной информации. Я делал это раньше с простыми спрайтами. Но если необходимая информация станет более сложной, чем простое число или индекс, я бы порекомендовал создавать подклассы узлов, а не пытаться спрятать вещи в неиспользуемые биты.