SpriteKit: хэширование переработанного SKShapeNode


Я пытаюсь обнаружить коллизии между узлами, которые не сталкивались раньше в моей игре SpriteKit, вызывая узел.хэширование и хранение новых узлов в наборе. Я вижу, что через некоторое время новые узлы имеют тот же хэш, что и узлы, которые я ранее называл узлом.removeFromParent () ВКЛ.

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

Как я могу получить действительно уникальный хэш из узлов в SpriteKit?

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

Кроме того, я не могу воспроизвести эту проблему, когда я отлаживаю свой телефон, подключенный к xcode, но я добавил ведение журнала, которое показывает узел.хэш не является уникальным для вновь созданных узлов. Кто-нибудь знает, почему поведение утилизации будет отличаться с моим телефоном, подключенным к Xcode?

3 2

3 ответа:

Я думаю, что вы, возможно, неправильно понимаете, что такое хэш и что он делает.

Хэш не обязательно является уникальным значением. Это односторонняя функция некоторого вида (не обязательно криптографическая), которая принимает произвольные данные и производит значение. Если одни и те же данные хэшируются более одного раза, они будут иметь одно и то же значение хэша, а не другое значение.

Работает против вас, однако, тот факт, что значение .hash является не криптографическим хэшем (что несколько вычислительно интенсивный). Качество хэш-функции, криптографической или нет, зависит от того, как часто происходят хэш-коллизии . Столкновение хэшей происходит, когда два различных значения производяттот же самый хэш.

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

Гораздо лучшим решением является добавьте свойство к вашим узлам, которое можно легко проверить:

class MyNodeClass: SkShapeNode {
   var hasCollided = false  // Publicly accessible property
}
Я замечаю, что в других комментариях вы говорите: "мне интересно найти правильный хэш."Я бы настоятельно рекомендовал отказаться от этого подхода, так как, опять же, хэш-функции определенно будут нести вычислительную нагрузку. Чем лучше функция, тем выше нагрузка.

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

SKNode использует реализацию NSObject по умолчанию hash , которая просто возвращает адрес памяти

import Foundation
import SpriteKit

let node  = SKNode()
let hex   = String(node.hash, radix:16)
let addr  = unsafeAddressOf(node)

print(hex)    // 7f9a21d080a0
print(addr)   // 0x00007f9a21d080a0

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

Чтобы получить уникальный хэш, вам нужно переопределить метод hash вашего SKNode и заставить его вернуть что-то действительно уникальное. Простой стратегией было бы назначить каждому узлу id свойство при создании чего-то вроде

class MyNode : SKNode {
    var uid:Int

    init(uid:Int) {
        self.uid = uid
        super.init()
    }

    override var hash:Int { get {
        return self.uid
    }}

    required init(coder aDecoder: NSCoder) {
        fatalError("not implemented, required to compile")
    }
}

Если вы начинаете счетчик с Int.min и увеличиваете его до Int.max, вам придется создать узлы 18,446,744,073,709,551,613, прежде чем вы исчерпаете уникальность.

Если я правильно вас понял, Вы, кажется, пытаетесь определить, сталкиваетесь ли вы с новыми объектами. Что вы можете сделать, это просто создать пользовательский SKShapeNode объект с логическим свойством. Это устранило бы необходимость иметь дело с сталкивающимися хэшами и вместо этого обеспечило бы надежный метод проверки, был ли узел обработан.

class CustomShapeNode: SKShapeNode {
    var hasAlreadyCollided = false

    // Any required overidden methods
}