Goal: SceneKit hit test with SwiftUI (instead of UIKit)
Problem: When I embed the default ship scene on a SwiftUI "UIViewRepresentable", the example handleTap function doesn't work. and I get his error:
"Argument of '#selector' refers to instance method 'handleTap' that is not exposed to Objective-C"
How an I create a hit test, and pass data to another SwiftUI view?
import SwiftUI
import SceneKit
var handleTap: (() -> Void)
struct ScenekitView : UIViewRepresentable {
let scene = SCNScene(named: "ship.scn")!
func makeUIView(context: Context) -> SCNView {
// create and add a camera to the scene
let cameraNode = SCNNode()
cameraNode.camera = SCNCamera()
scene.rootNode.addChildNode(cameraNode)
// place the camera
cameraNode.position = SCNVector3(x: 0, y: 0, z: 15)
// retrieve the ship node
let ship = scene.rootNode.childNode(withName: "ship", recursively: true)!
// retrieve the SCNView
let scnView = SCNView()
return scnView
}
func updateUIView(_ scnView: SCNView, context: Context) {
scnView.scene = scene
// allows the user to manipulate the camera
scnView.allowsCameraControl = true
// show statistics such as fps and timing information
scnView.showsStatistics = true
// configure the view
scnView.backgroundColor = UIColor.black
// add a tap gesture recognizer
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleTap(_:)))
scnView.addGestureRecognizer(tapGesture)
}
func handleTap(_ gestureRecognize: UIGestureRecognizer) {
// retrieve the SCNView
let scnView = SCNView()
// check what nodes are tapped
let p = gestureRecognize.location(in: scnView)
let hitResults = scnView.hitTest(p, options: [:])
// check that we clicked on at least one object
if hitResults.count > 0 {
// retrieved the first clicked object
let result = hitResults[0]
// get material for selected geometry element
let material = result.node.geometry!.firstMaterial
// highlight it
SCNTransaction.begin()
SCNTransaction.animationDuration = 0.5
// on completion - unhighlight
SCNTransaction.completionBlock = {
SCNTransaction.begin()
SCNTransaction.animationDuration = 0.5
material?.emission.contents = UIColor.black
SCNTransaction.commit()
}
material?.emission.contents = UIColor.green
SCNTransaction.commit()
}
}
}
#if DEBUG
struct ScenekitView_Previews : PreviewProvider {
static var previews: some View {
ScenekitView()
}
}
#endif