我在iOS 11(测试版)上使用ARKit和SceneKit编写iOS应用程序。
该应用程序将许多项目添加到增强现实场景中。为了识别每个项目,我将SCNNode子类化为MySCNNode,并在其中添加了id
字段:
MySCNNode: SCNNode {
var id: Int
...some initializer to assign value to the id
}
我还实现了
touchesBegan
委托方法。当用户触摸某个项目时,我想检索其对应的id
。所以我尝试将该项目的对应SCNNode
转换回MySCNNode
:override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesBegan(touches, with: event)
// hitTest to retrieve item's id
if let touchLocation = touches.first?.location(in: sceneLocationView) {
DDLogDebug("received touch location")
if let hit = sceneLocationView.hitTest(touchLocation, options: nil).first {
DDLogDebug("received a hit")
if let scnNode = hit.node as? SCNNode {
DDLogDebug("received a scnNode)")
if let mySCNNode = scnNode as? MySCNNode {
DDLogDebug("received a MySCNNode") // ====> Never reaches here
}
}
return
}
}
}
但是,从
SCNNode
转换为MySCNNode
的步骤永远不会发生在上述命中测试中尝试将SCNNode投射回MySCNNode时,是否写错了地方?是否有其他方法可以将其他信息存储在SCNNode中并在以后检索它?
谢谢
最佳答案
首先,您不需要id
。相反,您可以使用现有的name
属性。但是,如果要检查节点的类型,还应该检查它的父节点,因为hitTest
结果节点从子节点开始。您可以添加SCNNode扩展:
extension SCNNode {
/// Returns parent node of specified type.
///
/// - Returns: An optional `SCNNode` of specified `T` class type.
func parentOfType<T: SCNNode>() -> T? {
var node: SCNNode! = self
repeat {
if let node = node as? T { return node }
node = node?.parent
} while node != nil
return nil
}
}
然后使用:
if let myNode = node.parentOfType() as? MySCNNode {
// do something
}