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
How to Make JSON Data Persistent for Offline Use (Swift 4)
Shared Cookies with Wkprocesspool for Wkwebview in Swift
How to Get a Double Value Up to 2 Decimal Places
Swift Enumeration Order and Comparison
Swiftui, Shadow Only for Container
Iterating Over an Nsorderedset
Gmsplace Returns Invalid Coordinate (-180, -180), But Name and Place Id Are Correct
Captureoutput Function Isn't Called Using Setsamplebufferdelegate
How to Access Cfdictionary in Swift 3
"Use Default Container" Doesn't Show in Icloud Capabilities
Swift "Is" Operator with Type Stored in Variable
Swift Find Superview of Given Class with Generics
Adding a Custom Font to MACos App Using Swift
How to Remove Top Space of 'Form' in Swiftui
Swift Packages and Conflicting Dependencies
Firebase Retrieve Image from Url Save with Firebase Database