Scenekit gesture recognizer and overlaySKScene touches - ios

Currently working on a game with scene kit in swift. I've got a joystick added to a SKScene, which is then attached to my scene kit game scene. Typical HUD overlay for controls.
let hudScene = SKScene(size: view.frame.size)
scnView.overlaySKScene = hudScene
I have also added a joystick to hudScene and want to add some buttons. Now, all of this works fine until I add a gesture recognizer to my main game scene. Once I do, all tap interaction with the hudScene is completely ignored. Even if I tap on the joystick and log what node was tapped at that location, it gives me the node in my game scene and completely ignores the nodes in hudScene.
Can anybody provide any insight into why this is happening?
For reference, the touch events for the joystick are implemented from this library, and my gesture recognizer is implimented like this:
let touchDownRec = UILongPressGestureRecognizer(target: self, action: #selector(didTouchDown(_:)) )
touchDownRec.minimumPressDuration = 0
touchDownRec.numberOfTouchesRequired = 1
scnView.addGestureRecognizer(touchDownRec)

I had the same problem... you have to replace the touchesBegan with a TapGesture, or replace the UILongPressGestureRecognizer with touchesEnded, but is more precise the first option.

Related

UITapGestureRecognizer - Detecting if there's a sprite at tap location (swift)

I'm making an iOS game and need to know how to get the location of tap for uitapgesturerecognizer. I do NOT want to use touchesBegan, touchesEnded, etc. I also need to know how to check if a user double tapped the sprite node. I already have set up uitapgesturerecognizer's all I need to know is how to find the location of touch and see if it is the same location as a sprite node.
Any help is greatly appreciated!
Assuming your sprite is of a class that inherits from UIView (and I think they generally are) the handler function for the gesture recognizer should look like this.
func handleDoubleTap(gestureRecognizer: UITapGestureRecognizer) {
let tapLocation = gestureRecognizer.location(in: gestureRecognizer.view)
if mySprite.frame.contains(tapLocation){
print("tapped")
}
}

Disable camera panning in SceneKit

If I am using the default camera control in SceneKit, is there a way to disable the two fingered pan function and leave the others as they are?
I want users to be able to rotate and zoom an object, but not move it at all.
The sceneView already has a UIPanGestureRecognizer attached.
If you modify its maximumNumberOfTouches to be 1, you can disable the pan gesture.
for reco in sceneView.gestureRecognizers! {
if let panReco = reco as? UIPanGestureRecognizer {
panReco.maximumNumberOfTouches = 1
}
}
No. You'll have to make your own camera and use gesture recognizers.

TouchesBegan delay on left hand side of the display

On iPhone's with 3D touch enabled, there is a feature where long pressing the left hand side of the screen with enough force opens lets you change which app is active. Because of this, when a non-moving touch happens on the left hand side of the screen, the touch event is delayed for a second or two until the iPhone verifies that the user is not trying to switch tasks and is interacting with the app.
This is a major problem when developing a game with SpriteKit, as these touches are delayed by a second every time a user taps/holds their finger on the left edge of the screen. I was able to solve this problem by registering a UILongPressGestureRecognizer in the main Scene of the game, thus disabling TouchesBegan and implementing a custom touches function (used as a selector by the gesture recognizer):
-(void)handleLongPressGesture:(UITapGestureRecognizer *)gesture {
CGPoint location = [gesture locationInView:self.view];
if (gesture.state == UIGestureRecognizerStateBegan)
{
//
}
else if (gesture.state == UIGestureRecognizerStateChanged)
{
//
}
else if (gesture.state == UIGestureRecognizerStateEnded)
{
//
}
else if (gesture.state == UIGestureRecognizerStateCancelled)
{
//
}
}
-(void)didMoveToView:(SKView *)view {
/* Setup your scene here */
UILongPressGestureRecognizer *longPressGestureRecognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(handleLongPressGesture:)];
longPressGestureRecognizer.delaysTouchesBegan = false;
longPressGestureRecognizer.minimumPressDuration = 0;
[view addGestureRecognizer:longPressGestureRecognizer];
// continue
}
The problem with this is that I would have to implement a gesture recognizer for every touch (including simultaneous ones) that I expect the user to enter. This interferes with any touchesBegan methods as subclasses of SKSpriteNode, SKScene, etc. and kills a lot of functionality.
Is there any way to disable this delay? When registering the gestureRecognizer, I was able to set delaysTouchesBegan property to false. Can I do the same somehow for my SKScene?
To see this issue in action, you can run the default SpriteKit project, and tap (hold for a second or two) near the left hand side of the screen. You will see that there is a delay between when you touch the screen and when the SKShapeNodes are rendered (as opposed to touching anywhere else on the screen).
* Edit 1 *
For those trying to find a way to get around this for now, you can keep the gesture recognizer but set its cancelsTouchesInView to false. Use the gesture recognizer to do everything you need to do until TouchesBegan kicks in (touchesBegan will receive the same touch event about a second after the gesture recognizer recognizes the touch). Once touchesBegan kicks in, you can disable everything happening in the gesture recognizer. This seems like a sloppy fix to me, but it works for now.
Still trying to find a more-or-less formal solution.
I have experienced this as an user and it is really annoying. The only thing that worked for me was to disable the 3D touch. Otherwise the left side of the touchscreen is almost useless.

Making a node go in the direction of a swipe (Swift)

I'm making a game in SpriteKit using Swift, and I want to be able to swipe on the screen and have a ball go in that direction. I already have the ball created and its just named "ball" as an SKSpriteNode. I already have it moving around the screen but I just need it to change directions towards swipes that take place. If I can't do this with swipes then I would consider taps.
Also, I have a border the size of the screen. Here is the code for that:
let worldBorder = SKPhysicsBody(edgeLoopFromRect: self.frame)
self.physicsBody = worldBorder
self.physicsBody?.friction = 0
The border is already functioning as a border, but I need to keep it that way for when I start swiping.

UISwipeGestureRecognizer with SpriteKit using Swift

I am creating a game in swift that involves making words out of letters. The letters, which are individual SKSpriteNodes, sit on a "shelf" which is a SKSpriteNode. To remove the letters from the "shelf", I am trying to introduce swiping up. Unfortunately I am having issues with the swipe being picked up by the letters. The shelf seems to be absorbing it, or sometimes even the SKScene. I have disabled the user interaction on the shelf node.
This is my setup:
swipeRecognizer = UISwipeGestureRecognizer(target: self, action: Selector("move:"))
swipeRecognizer.direction = UISwipeGestureRecognizerDirection.Up
self.view.addGestureRecognizer(swipeRecognizer)
I add the swipeRecognizer to the view, then in the move method, I have the following:
func move(swipe:UISwipeGestureRecognizer){
if(swipe.state == UIGestureRecognizerState.Ended && swipe.numberOfTouches() == 1){
var touchLocation = swipe.locationInView(swipe.view)
touchLocation = self.convertPointFromView(touchLocation)
var sprite = self.nodeAtPoint(touchLocation)
if sprite is Letter{
let letter = sprite as Letter
if(gameManager.letterOnShelf(letter)){
gameManager.letterFlicked(letter)
}
}
}
}
Only sometimes to it recognize the sprite as a letter, 80% of the time the sprite is the shelf and I can't figure out what the correct way to work it is.....
Any help is greatly appreciated.
Cheers all!!
I would recommend:
Using a UILongPressGestureRecognizer with minimumPressDuration set to 0.
When the gesture is at the UIGestureRecognizerStateBegan state, see if the sprite your touch is over is a Letter and save a reference to that tile.
In the UIGestureRecognizerStateEnded state, you should be able to see what location your gesture ended (or perhaps the trajectory, etc) and then move the tile you stored a reference to from earlier.

Resources