0

Changing NSClickGestureRecognizer to a NSPanGestureRecognizer in a SceneKit MacOS Game Template app and the camera rotate no longer works.

For example if one generates a new MacOS Game template app and then change the line:

let clickGesture = NSClickGestureRecognizer(target: self, action: #selector(handleClick(_:)))

to:

let clickGesture = NSPanGestureRecognizer(target: self, action: #selector(handleClick(_:)))

Then the rotate camera gesture no longer works.

Andy Jazz
  • 49,178
  • 17
  • 136
  • 220
bhartsb
  • 1,316
  • 14
  • 39
  • this might be due to a conflict between the new pan recognizer and the allowsCameraControl option, which also uses a pan handler - if you use this feature – ZAY Dec 05 '22 at 06:53
  • @ZAY That is a good guess, but if that is the case the gesture recognizer for the camera is not in the VC's list of recognizers (maybe in a superview). I tried the following but it isn't being called - func gestureRecognizer(_ gestureRecognizer: NSGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: NSGestureRecognizer) -> Bool { return true } – bhartsb Dec 05 '22 at 07:44

1 Answers1

1

This is due to the nature of the NSPanGestureRecognizer. In order for the Hit-Test to work for your model, you need to click on the mouse button, then drag it some distance, and then release it. The exact same action is required to pan or orbit the camera when the .allowsCameraControl property is true. Thus, by default, NSPanGestureRecognizer blocks the gestures of the camera controller because the first one has a higher priority in SceneKit. Setting priority is a common practice to avoid conflicts between objects with similar behaviors.

By default, this gesture recognizer blocks the gestures for the camera:

let panGesture = NSPanGestureRecognizer(target: self, 
                                        action: #selector(handlePan))

panGesture.buttonMask = 1               // default

To do the opposite, use:

panGesture.buttonMask = 0

Unlike its counterpart, NSClickGestureRecognizer needs you to simply click (not drag) the model.

Andy Jazz
  • 49,178
  • 17
  • 136
  • 220
  • 1
    If I change to NSClickGestureRecognizer then I get a conflict with other subview Gesture recognizers. I've tried implementing func gestureRecognizer( _ gestureRecognizer: NSGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: NSGestureRecognizer ) -> Bool { return true } And I set the gesture.delegate = VC, and VC is UIGestureRecognizerDelegate, but it isn't getting called. – bhartsb Dec 06 '22 at 06:18
  • 1
    The solution I found per a NSClickGestureRecognizer not playing well with some subviews having NSButtons and actions was to subclass it and override func mouseDown(...), get the location in superview, then for each subview see if subview.frame contains the location in superview and if yes call self.touchesCancelled(with: event). This is another post that describes the NSButton issue: https://stackoverflow.com/questions/50548211/how-make-custom-view-and-over-its-nsbutton-is-clickable-in-macos-swift – bhartsb Dec 06 '22 at 11:41
  • Hey @bhartsb, could you thoroughly describe your problem in separate question (providing the code) ? – Andy Jazz Dec 06 '22 at 19:15
  • 1
    Hi Andy, per my comment above I found a solution for the NSButton issue with touchesCancelled. For the pan gesture recognizer issue with the rotate camera I use the click gesture recognizer to disable it when clicking on a node with geometry and enable it when clicking outside the node. Thank you for your help. – bhartsb Dec 08 '22 at 09:39