Search code examples
iosswiftscenekitswift-playground

func hitTest declared in SceneKit causes crash in Playground


I create a scene in playground and use hitTest (func hitTest(_ point: CGPoint, options: [SCNHitTestOption : Any]? = nil) -> [SCNHitTestResult]) function to determine if one of the nodes has been touched, but it causes a crash of simulator in playground only when nodes are touched. This does not happen with the same code on iOS project with xcode.

func panGesture(sender: UIPanGestureRecognizer) {
    sender.view

    let translation = sender.translation(in: sender.view!)

    var newAngleX = (Float)(translation.y)*(Float)(M_PI)/180.0
    newAngleX += currentXAngle
    var newAngleY = (Float)(translation.x)*(Float)(M_PI)/180.0
    newAngleY += currentYAngle

    if (sender.numberOfTouches>0){

        var point = sender.location(in: self)

        print(point)

        let hit = self.hitTest(point, options: nil)

        let node = hit.first?.node

        node?.eulerAngles.x = newAngleX
        node?.eulerAngles.y = newAngleY

        if(sender.state == UIGestureRecognizerState.ended) {
            currentXAngle = newAngleX
            currentYAngle = newAngleY
        }

    }

}

Solution

  • This runs really, really, really slow in Playground... but maybe there's something else going on. Anyway, if you replace your func panGesture(sender: UIPanGestureRecognizer) with this, it should at least let you run it in the Playground without crashing.

    func panGesture(sender: UIPanGestureRecognizer) {
        sender.view
    
        let translation = sender.translation(in: sender.view!)
    
        var newAngleX = (Float)(translation.y)*(Float)(M_PI)/180.0
        newAngleX += currentXAngle
        var newAngleY = (Float)(translation.x)*(Float)(M_PI)/180.0
        newAngleY += currentYAngle
    
        let point = sender.location(in: self)
        print(point)
    
        // important
        guard let hit = self.hitTest(point, options: nil) as? [SCNHitTestResult] else { return }
    
        // and, don't go in here if hit.count == 0, because it won't have a .first
        if (sender.numberOfTouches > 0 && hit.count > 0){
    
            let node = hit.first?.node
    
            node?.eulerAngles.x = newAngleX
            node?.eulerAngles.y = newAngleY
    
            if(sender.state == UIGestureRecognizerState.ended) {
                currentXAngle = newAngleX
                currentYAngle = newAngleY
            }
    
        }
    
    }