Good afternoon, I'm trying to figure out how to get touch notifications from an SCNNode & a SKSpriteNode from an SCNScene overlayed with a SKScene.
import UIKit
import SceneKit
class GameViewController: UIViewController {
var scnView:SCNView!
var scnScene:SCNScene!
var sprite: spritekitHUD!
var cameraNode: SCNNode!
var shape: SCNNode!
override func viewDidLoad() {
super.viewDidLoad()
setupScene()
}
func setupScene() {
scnView = self.view as! SCNView
scnView.delegate = self
scnView.allowsCameraControl = true
scnScene = SCNScene(named: "art.scnassets/scene.scn")
scnView.scene = scnScene
sprite=spritekitHUD(size: self.view.bounds.size, game: self)
scnView.overlaySKScene=sprite
cameraNode = scnScene.rootNode.childNode(withName: "camera",
recursively: true)!
shape=scnScene.rootNode.childNode(withName: "shape", recursively: true)
shape.name="ThreeDShape"
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?)
{
let touch = touches.first!
let location = touch.location(in: scnView)
let hitResults = scnView.hitTest(location, options: nil)
if let result = hitResults.first {
handleTouchFor(node: result.node)
}
}
func handleTouchFor(node: SCNNode) {
if node.name == "ThreeDShape" {
print("SCNNode Touched")
}
}
}
This is my Spritekit overlay scene
import Foundation
import SpriteKit
class spritekitHUD: SKScene{
var game:GameViewController!
var shapeNode: SKSpriteNode!
init(size: CGSize, game: GameViewController){
super.init(size: size)
self.backgroundColor = UIColor.white
let spriteSize = size.width/12
self.shapeNode= SKSpriteNode(imageNamed: "shapeNode")
self.shapeNode.size = CGSize(width: spriteSize, height: spriteSize)
self.shapeNode.position = CGPoint(x: spriteSize + 8, y: spriteSize + 8)
self.shapeNode.name="test"
self.game=game
self.addChild(self.pauseNode)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
guard let touch=touches.first else{
return
}
let location=touch.location(in: self)
if self.atPoint(location).name=="test" {
print("Spritekit node pressed")
}
}
}
so with this I can successfully get notifications that my spritenode has been touched on my overlaySKScene but I cant figure out how to get a notification that my SCNode has been touched. If you cant have 2 touchesbegan functions does anyone have any ideas how I can handle the 3d events with 2d events at the same time?
Thanks for your help!!
If you want to use an SKScene
overlay of an SCNView
for user controls, (eg you want to implement a button in the SKScene overlay that "consumes" the touch), but also have touches that don't hit the controls to pass through and register in the underlying SCNView
, you have to do this: set isUserInteractionEnabled
to false
on the SKScene overlay itself, but then to true
on any individual elements within that overlay that you'd like to act as buttons.
let overlay = SKScene(fileNamed: "overlay")
overlay?.isUserInteractionEnabled = false
let pauseButton = overlay?.childNode(withName: "pauseButton") as? Button
// Button is a subclass of SKSpriteNode that overrides touchesEnded
pauseButton?.isUserInteractionEnabled = true
sceneView.overlaySKScene = overlay
If the user touches a button, the button's touch events (touchesBegan
, touchesEnded
etc) will fire and consume the touch (underlying gesture recognizers will still fire though). If they touch outside of a button however, the touch will pass through to the underlying SCNView.
This is "lifted" straight out of Xcode's Game template......
Add a gesture recognizer in your viewDidLoad:
// 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 = self.view as! 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: AnyObject = hitResults[0]
// result.node is the node that the user tapped on
// perform any actions you want on it
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With