Placing a SCNNode on a plane and detecting that the node is tapped

1.2k views Asked by At

I'm working on an app which first detect that there is a vertical plane, and after that, if the user touches the plane I add a SCNNode to the rootNode. After that, I want to detect if the user touches the node to do more things, but I'm not able to detect that tap, it just detects plane taps. Right now I've come back to this method:

    @objc func tapped(sender: UITapGestureRecognizer) {
        let sceneView = sender.view as! ARSCNView
        let tapLocation = sender.location(in: sceneView)
        let hitTest = sceneView.hitTest(tapLocation, types: .existingPlaneUsingExtent)
        if !hitTest.isEmpty {
            addItem(hitTestResult: hitTest.first!)
            hideTip()
    }
}

Which is the one that add a node when tapping on the plane, but now I want to detect when the node is tapped, I've used this code:

    let sceneView = sender.view as! ARSCNView
    let tapLocation = sender.location(in: sceneView)
    let hitTouchTest = sceneView.hitTest(tapLocation)
    if !hitTouchTest.isEmpty {
        let results = hitTouchTest.first!
        let node = results.node
    }

And it enters the if, but the name of the node is always nil, and when I create the node adding it to the plane I give it a name... How can I detect that the node is tapped?

1

There are 1 answers

2
Yevhen On BEST ANSWER

The problem with this solution is that you taking the first value of an array of nodes that been touched. I recommend to read next topic: https://developer.apple.com/documentation/scenekit/scnhittestoption

And solution that you can implement:

func registerGestureRecognizer() {
    let tap = UITapGestureRecognizer(target: self, action: #selector(search))
    self.sceneView.addGestureRecognizer(tap)
}

@objc func search(sender: UITapGestureRecognizer) {
    let sceneView = sender.view as! ARSCNView
    let location = sender.location(in: sceneView)
    let results = sceneView.hitTest(location, options: [SCNHitTestOption.searchMode : 1])

    guard sender.state == .began else { return }
        for result in results.filter( { $0.node.name != nil }) {
            if result.node.name == "Your node name" {
                // do manipulations
            }
        }
}

P.S. This approach helps you to get specific node via its name. Hope it helps!