Swift/Scenekit Problems Getting Touch Events from Scnscene and Overlayskscene

swift/scenekit problems getting touch events from SCNScene and overlaySKScene

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

}
}

How to properly encapsulate touch event handling in a SKSpriteNode and pass data back to a SKScene

I like to handle as much of the code in the object class as possible. So I would handle any of the object touch code inside of it's class file and send the touch back to the scene to be handle separately by the scene if needed, and use delegation to send the information regarding the touch to the scene.

There are no downsides to removing this code, and several upsides.

cleaner code
faster loading time in xcode if the scenes have less line (my own findings)
you don't have to pinpoint the node that the touch is landing on because it is encapsulated in a sublass

In subclass (cat)

protocol CatDelegate: class{
func catTouched(cat: Cat)
}

class Cat: SKSpriteNode {

weak var delegate: CatDelegate!

var isEnabled = true
var sendTouchesToScene = true
var color: SKColor = .white

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent!) {

guard isEnabled else { return }

//send touch to scene if you need to handle further touches by the scene
if sendTouchesToScene {
super.touchesBegan(touches, with event)
}

//handle touches for cat
delegate?.catTouched(cat: self)
}
}

meanwhile in Game Scene...

class GameScene: SKScene {

private var cat1: Cat!
private var cat2: Cat!



func createCats() {

cat1 = Cat()
cat1.color = .magenta
cat1.delegate = self
addChild(cat1)

cat2 = Cat()
cat2.color = .green
cat2.delegate = self
addChild(cat2)
}
}

extension GameScene: CatDelegate {

func catTouched(cat: Cat) {
print("cat of color \(cat.color)")
}
}

SpriteKit - Why SKNode's are not being touch detected

I had a similar issue (background in z: 999 + spawning "ducks" nodes in z: <999) that I solved with the following code in Swift 4:

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
let touch:UITouch = touches.first!
let positionInScene = touch.location(in: self)
let touchedNodes = self.nodes(at: positionInScene)
for touch in touchedNodes {
let touchName = touch.name
if (touchName != nil && touchName!.hasPrefix("pato_")) {
touch.removeFromParent()
}
}
}

Get vector in SCNNode environment from touch location swift

You can use the SCNSceneRenderer.unprojectPoint(_:) method for this.

This method, which is implemented by SCNView, takes the coordinates of your point as a SCNVector3. Set the first two elements in the coordinate space of your view. Apple describes the use of the third element:

The z-coordinate of the point parameter describes the depth at which to unproject the point relative to the near and far clipping planes of the renderer’s viewing frustum (defined by its
pointOfView
node). Unprojecting a point whose z-coordinate is 0.0 returns a point on the near clipping plane; unprojecting a point whose z-coordinate is 1.0 returns a point on the far clipping plane.

You are not looking for the location of these points, but for the line that connects them. Just subtract both to get the line.

func getDirection(for point: CGPoint, in view: SCNView) -> SCNVector3 {
let farPoint = view.unprojectPoint(SCNVector3Make(point.x, point.y, 1))
let nearPoint = view.unprojectPoint(SCNVector3Make(point.x, point.y, 0))

return SCNVector3Make(farPoint.x - nearPoint.x, farPoint.y - nearPoint.y, farPoint.z - nearPoint.z)
}


Related Topics



Leave a reply



Submit