我试图通过调用node.hash并在一个集合中存储新节点来检测之前在我的SpriteKit游戏中没有发生冲突的节点之间的冲突。我看到一段时间后,新节点与我以前称之为node.removeFromParent()的节点具有相同的哈希值。
我猜这是因为我要从父节点中删除并一遍又一遍地重新创建非常相似的节点,SK会自动回收一些节点。
如何从SpriteKit中的节点获取真正唯一的哈希?
如果需要进一步说明,请与我们联系。我觉得发布我的代码与这篇文章不太相关。
此外,当我使用连接到xcode的手机进行调试时,我无法重现此问题,但我添加了日志,显示node.hash对于新创建的节点不是唯一的。有人知道为什么我的手机连接到Xcode的回收行为会有所不同吗?
答案 0 :(得分:3)
我认为你可能会误解哈希是什么和做什么。
哈希不一定是唯一值。它是某种单向函数(不一定是加密函数),它接受任意数据并产生一个值。如果对同一数据进行多次哈希处理,则会产生相同的哈希值,而不是不同的值。
然而,与你对抗的是,.hash
值不加密哈希(这在某种程度上是计算密集型的)。哈希函数的质量(加密与否)基于哈希冲突的频率。当两个不同的值产生相同的哈希时,就会发生哈希冲突。
除其他之外,基于低哈希冲突率选择加密哈希函数。即使您的数据不同,.hash
功能也可能具有较高的冲突率,具体取决于您的特定数据。
更好的解决方案是向您的节点添加一个易于检查的属性:
class MyNodeClass: SkShapeNode {
var hasCollided = false // Publicly accessible property
}
我注意到在其他评论中你说,"我很有兴趣找到合适的哈希。"我强烈建议不要采用这种方法,因为哈希函数肯定会带来计算负荷。功能越好,负载越高。
如果你真正想要的是每个节点(而不是碰撞跟踪器)的唯一标识符,那么为什么不实现一个内部属性,该内部属性是基于一个只产生唯一递增ID的类值从初始化器初始化的?
答案 1 :(得分:1)
SKNode
正在使用NSObject
的{{1}}默认实现,它只返回一个内存地址
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
的{{1}}方法并让它返回实际上唯一的哈希值。一个简单的策略是在创建时为每个节点分配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
个节点。
答案 2 :(得分:0)
如果我理解正确,你似乎在试图确定你是否与新物体相撞。你可以做的只是创建一个带有boolean属性的自定义SKShapeNode对象。这将消除处理冲突哈希的需要,而是提供一种检查节点是否已被处理的万无一失的方法。
class CustomShapeNode: SKShapeNode {
var hasAlreadyCollided = false
// Any required overidden methods
}