如何检测哪个 SCNNode 被触摸了 ARKit
How to detect which SCNNode has been touched ARKit
我在 SCNode 命中检测方面遇到了一些问题。我需要检测在具有 SCNNode 的场景中触摸了哪个对象,我已经实现了这段代码,但是当我触摸对象时它似乎崩溃了但是当我触摸场景视图的其余部分时它工作正常。
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
let touch = touches.first as! UITouch
if(touch.view == self.sceneView){
print("touch working")
let viewTouchLocation:CGPoint = touch.location(in: sceneView)
guard let result = sceneView.hitTest(viewTouchLocation, options: nil).first else {
return
}
if (bottleNode?.contains(result.node))! { //bottleNode is declared as SCNNode? and it's crashing here
print("match")
}
}
}
您当前正在测试您的 SCNNode 是否“包含”来自最命中结果的节点,而您应该简单地比较它们,即 if (bottlenode == result.node)...
你真的创建了一个bottleNode
吗?如果 bottleNode
为 nil,表达式 bottleNode?.contains(result.node)
也将为 nil,因此当您强制展开它时,它会抛出错误。
如果您知道 bottleNode 将始终被定义,那么它不应该是可选的。如果您不知道,则需要在使用前检查它是否存在。这应该可以满足您的要求:
if let bottleNode = bottleNode, bottleNode.contains(result.node) {
请注意,如果 bottleNode 不存在,此测试将自动失败。
可能是,bottleNode
为零。什么线路导致崩溃?比较前检查bottleNode
是否存在:
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
let touch = touches.first as! UITouch
if(touch.view == self.sceneView){
print("touch working")
let viewTouchLocation:CGPoint = touch.location(in: sceneView)
guard let result = sceneView.hitTest(viewTouchLocation, options: nil).first else {
return
}
if let bottleNode = bottleNode, bottleNode == result.node { //bottleNode is declared as SCNNode? and it's crashing here
print("match")
}
}
}
这里有多个问题,现有的答案只解决了其中的一部分。
从您发布的代码中不清楚当此方法运行时 bottleNode
是否可以为 nil。通过可选值(bottle?.contains
中的 ?
)调用一个方法,当它的值为 nil 时会无提示地失败——导致整个表达式结果包装在一个值为 nil 的 Optional 中——但是你有括号和一个力展开整个表达式,所以 nil-unwrap 会崩溃。
contains(_:)
不是 SCNNode
上的方法。目前还不清楚你的 bottleNode
可能是什么类型,你甚至可以在不出现编译器错误的情况下编写这个方法调用......但是如果 bottleNode
实际上是一个 SCNNode
并且你已经做了一些类型 -擦除/Any
-casting goop 以允许编译调用,由于方法不存在,调用将在运行时失败。
如果您使用 bottleNode.contains
行的目标是确定命中测试结果是 bottleNode
本身还是其子节点,我建议定义和使用这样的扩展方法:
extension SCNNode {
func hasAncestor(_ node: SCNNode) -> Bool {
if self === node {
return true // this is the node you're looking for
}
if self.parent == nil {
return false // target node can't be a parent/ancestor if we have no parent
}
if self.parent === node {
return true // target node is this node's direct parent
}
// otherwise recurse to check parent's parent and so on
return self.parent.hasAncestor(node)
}
}
// in your touchesBegan method...
if let bottleNode = bottleNode, result.node.hasAncestor(bottleNode) {
print("match")
}
如果您的目标是确定 result.node
是否位于 bottleNode
的边界框内或与其重叠(不考虑节点层次结构),则回答该问题会稍微复杂一些。 boundingSphere
中的简单 position
检查非常简单,或者如果您要查找 containment/overlap,octree 可能会有所帮助。
我在 SCNode 命中检测方面遇到了一些问题。我需要检测在具有 SCNNode 的场景中触摸了哪个对象,我已经实现了这段代码,但是当我触摸对象时它似乎崩溃了但是当我触摸场景视图的其余部分时它工作正常。
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
let touch = touches.first as! UITouch
if(touch.view == self.sceneView){
print("touch working")
let viewTouchLocation:CGPoint = touch.location(in: sceneView)
guard let result = sceneView.hitTest(viewTouchLocation, options: nil).first else {
return
}
if (bottleNode?.contains(result.node))! { //bottleNode is declared as SCNNode? and it's crashing here
print("match")
}
}
}
您当前正在测试您的 SCNNode 是否“包含”来自最命中结果的节点,而您应该简单地比较它们,即 if (bottlenode == result.node)...
你真的创建了一个bottleNode
吗?如果 bottleNode
为 nil,表达式 bottleNode?.contains(result.node)
也将为 nil,因此当您强制展开它时,它会抛出错误。
如果您知道 bottleNode 将始终被定义,那么它不应该是可选的。如果您不知道,则需要在使用前检查它是否存在。这应该可以满足您的要求:
if let bottleNode = bottleNode, bottleNode.contains(result.node) {
请注意,如果 bottleNode 不存在,此测试将自动失败。
可能是,bottleNode
为零。什么线路导致崩溃?比较前检查bottleNode
是否存在:
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
let touch = touches.first as! UITouch
if(touch.view == self.sceneView){
print("touch working")
let viewTouchLocation:CGPoint = touch.location(in: sceneView)
guard let result = sceneView.hitTest(viewTouchLocation, options: nil).first else {
return
}
if let bottleNode = bottleNode, bottleNode == result.node { //bottleNode is declared as SCNNode? and it's crashing here
print("match")
}
}
}
这里有多个问题,现有的答案只解决了其中的一部分。
从您发布的代码中不清楚当此方法运行时
bottleNode
是否可以为 nil。通过可选值(bottle?.contains
中的?
)调用一个方法,当它的值为 nil 时会无提示地失败——导致整个表达式结果包装在一个值为 nil 的 Optional 中——但是你有括号和一个力展开整个表达式,所以 nil-unwrap 会崩溃。contains(_:)
不是SCNNode
上的方法。目前还不清楚你的bottleNode
可能是什么类型,你甚至可以在不出现编译器错误的情况下编写这个方法调用......但是如果bottleNode
实际上是一个SCNNode
并且你已经做了一些类型 -擦除/Any
-casting goop 以允许编译调用,由于方法不存在,调用将在运行时失败。
如果您使用 bottleNode.contains
行的目标是确定命中测试结果是 bottleNode
本身还是其子节点,我建议定义和使用这样的扩展方法:
extension SCNNode {
func hasAncestor(_ node: SCNNode) -> Bool {
if self === node {
return true // this is the node you're looking for
}
if self.parent == nil {
return false // target node can't be a parent/ancestor if we have no parent
}
if self.parent === node {
return true // target node is this node's direct parent
}
// otherwise recurse to check parent's parent and so on
return self.parent.hasAncestor(node)
}
}
// in your touchesBegan method...
if let bottleNode = bottleNode, result.node.hasAncestor(bottleNode) {
print("match")
}
如果您的目标是确定 result.node
是否位于 bottleNode
的边界框内或与其重叠(不考虑节点层次结构),则回答该问题会稍微复杂一些。 boundingSphere
中的简单 position
检查非常简单,或者如果您要查找 containment/overlap,octree 可能会有所帮助。