我正在iOS 11(beta)上使用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中存储其他信息并在以后检索它?
谢谢
答案 0 :(得分:2)
首先,您不需要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
}
答案 1 :(得分:0)
我认为你走在正确的轨道上,但你不需要这么多的演员阵容,如果你“堆叠”if let
,它会更容易。试试这个:
if let touchLocation = touches.first?.location(in: sceneLocationView),
let hit = sceneLocationView.hitTest(touchLocation, options: nil).first,
let myNode = hit.node as? MySCNNode {
DDLogDebug("received a MySCNNode")
}