如何检测哪个SCNNode已被触摸ARKit

时间:2017-09-25 21:54:38

标签: swift scenekit arkit scnnode

我在SCNode命中检测方面遇到了一些麻烦。我需要检测在具有SCNNode的场景中触摸了哪个对象,我已经实现了这段代码但是当我触摸对象时它似乎崩溃但是当我触摸其余的sceneView时工作正常。

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")
            }

        }
    }

4 个答案:

答案 0 :(得分:5)

这里存在多个问题,现有的答案只针对其中一些问题。

  1. 在此方法运行时,您发布的代码中不清楚bottleNode是否为零。当值为nil时,通过可选(?中的bottle?.contains)调用方法会无声地失败 - 导致整个表达式结果换行为其值为nil的Optional - 但是你已经得到了parens和一个力量解开整个表达式,所以nil-unwrap会崩溃。

  2. contains(_:)不是SCNNode上的方法。目前还不清楚您的bottleNode可能是什么类型,甚至可以编写此方法调用而不会出现编译错误......但如果bottleNode实际上是SCNNode并且您是&#39 ;我做了一些类型擦除/ Any - 转换goop以允许调用编译,由于不存在的方法,调用将在运行时失败。

  3. 如果您使用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的边界框内或与position的边界框重叠(无论节点层次结构如何),那么回答这个问题会更复杂一些。 boundingSphere检查中的var express = require('express'); var app = express(); var serv = require('http').Server(app); app.get('/', function(req, res) { res.sendFile(__dirname + '/client/index.html'); }); app.use('/client', express.static(__dirname + '/client')); serv.listen(2000); console.log("Server started!"); var io = require('socket.io')(serv,{}); var md5 = require('md5'); var mysql = require('mysql'); var dbconn = mysql.createConnection({ host: "mySERVER", user: "myUSER", password: "myPASSWORD", database: "myDBNAME" }); dbconn.connect(function(err) { if (err) throw err; //THE ERROR IS THROWN HERE }); io.sockets.on("connection", function(socket) { socket.on("register", function(obj){ var sql = 'INSERT INTO users (name, password) VALUES ("' + obj.name + '", "' + md5(obj.password) + '")'; dbconn.query(sql, function (err, result) { if (err) throw err; console.log("Result: " + result); }); }); }); 非常简单,或者如果您正在寻找遏制/重叠,octree可能有帮助。

答案 1 :(得分:4)

可能是,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")
            }

        }
    }

答案 2 :(得分:1)

您目前正在测试SCNNode是否“包含”来自hittest结果的节点,而您应该只是比较它们,即if(bottlenode == result.node)......

答案 3 :(得分:1)

您是否真的创建了bottleNode?如果bottleNode为nil,则表达式bottleNode?.contains(result.node)也将为nil,因此当您强行打开它时,它将引发错误。

如果您知道将始终定义bottleNode,则它不应该是可选的。如果您不知道,在使用之前需要检查它是否存在。这应该做你想要的:

if let bottleNode = bottleNode, bottleNode.contains(result.node) {

请注意,如果bottleNode不存在,则此测试将无声地失败。