Peter Irving
Peter Irving

Reputation: 405

Manage Gestures Between Sprite Kit and Scene Kit

I am trying to create a sphere with selectable grid tiles. The sphere should be able to rotate and zoom in, while still allowing grid tiles to be selectable. From what I understand this can be accomplished by using a SceneKit Sphere and setting the diffuse.contents equal to a Sprite Kit Scene.

Currently, I have the Sphere present with the Sprite Kit Scene as a texture overlay. I am able to create hit tests that recognize x,y coordinates on the sphere, but I am not actually selecting any tiles. "node has no name" is printing, I assume nodes selected would be part of SceneKit, not the Sprite Kit texture.

I created this project as a platform view for a Flutter app, if that changes anything. Also the Sprite Kit Scene was created in a .scn file.

Any suggestions?


public class SceneKitViewFactory: NSObject, FlutterPlatformViewFactory {

    public func create(withFrame frame: CGRect, viewIdentifier viewId: Int64, arguments args: Any?) -> FlutterPlatformView {
        print("returning scene kit view")

            return SceneKitView(frame, viewId: viewId, args: args)

    }

}


public class SceneKitView: NSObject, FlutterPlatformView {
    let frame: CGRect
    let viewId: Int64
    let myScene: SCNScene
    let scnView: SCNView
    var cameraNode: SCNNode!


    init(_ frame: CGRect, viewId: Int64, args: Any?) {
        self.frame = frame
        self.viewId = viewId
        self.scnView = SCNView()
        self.myScene = SCNScene()
        scnView.scene = myScene
        scnView.backgroundColor = .green

        super.init()

        createSphere()
        createSceneHelpers()
        createCamera()

        let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleTap(_:)))
        tapGesture.cancelsTouchesInView = false
        scnView.addGestureRecognizer(tapGesture)
    }

    public func view() -> UIView {
        return scnView
    }

    private func createSphere() {

        let sphere = SCNSphere(radius: 1.0)
        let imageMaterial = SCNMaterial()

        let spriteKitScene  = SKScene(fileNamed: "GameScene")!
        spriteKitScene.isUserInteractionEnabled = true

        imageMaterial.diffuse.contents = spriteKitScene

        let sphereNode = SCNNode(geometry: sphere)
        sphereNode.geometry!.firstMaterial = imageMaterial

        myScene.rootNode.addChildNode(sphereNode)
    }

    private func createSceneHelpers() {
        scnView.showsStatistics = true
        scnView.allowsCameraControl = true
        scnView.autoenablesDefaultLighting = true
    }

    private func createCamera() {
        cameraNode = SCNNode()
        cameraNode.camera = SCNCamera()
        cameraNode.position = SCNVector3(x: 0, y: 0, z: 5)
        myScene.rootNode.addChildNode(cameraNode)
    }


     @objc func handleTap(_ gestureRecognize: UIGestureRecognizer) {


            let p = gestureRecognize.location(in: scnView)
            let hitResults = scnView.hitTest(p, options: [:])
            if hitResults.count > 0 {
            let result: SCNHitTestResult = hitResults[0]

            print(result.node.name ?? "node has no name")
            print(result.textureCoordinates(withMappingChannel: 0)) // This line is added here.
            print("x: \(p.x) y: \(p.y)") // <--- THIS IS WHERE I PRINT THE COORDINATES

            }
        }

}

Upvotes: 1

Views: 250

Answers (1)

Voltan
Voltan

Reputation: 1213

Name your node(s) when you create them -> node.name = "x". Depending on a few things, but generally a good practice to name your nodes uniquely (cameras, etc.) in case you have to iterate through a bunch of nodes to see what they are. Not sure that gets you all of the way home, but that could be the first issue. "Looks" like you are reading these posts: 35023170 so it seems you're heading in the right direction.

Might want to iterate for multiple results just to be sure you get the hit you want:

let hitResults = gameScene.hitTest(location, options: hitTestOptions)
for vHit in hitResults
{
   if(vHit.node.name?.prefix(5) == "Panel")
   {
   ...
   }
}

Upvotes: 0

Related Questions