Search code examples
iosswiftsprite-kituigesturerecognizertouchesbegan

touchesBegan Vs UITapGestureRecognizer


So I'm making a spritekit game using swift. And I was wondering which is best to use gesture wise?

Currently I have a override func touchesBegan handling all taps and a UILongPressGestureRecognizer handling long taps/holds.

So you know, a tap presses buttons and jumps the hero. The long hold makes the hero duck.

For some reason my longPress function isn't always called (sometimes you can press and hold 10 times and then it stops being called (isn't recognised), other times it's 5, it varies), and this led to a whole day yesterday trying new things and investigating, which brought me to this question.

Is it better to use touchesBegan or move all my touch calls to a new function handled by a UITapGestureRecognizer?

I did move everything from touchesBegan to UITapGestureRecognizer but it seems very sluggish. But I may have been implementing it wrong?

This is how the recognisers are set up:

func setupRecognizers() {
    let tapRecognizer = UITapGestureRecognizer(target: self, action: Selector("handleTap:"))
    view!.addGestureRecognizer(tapRecognizer)

    let longTapRecognizer = UILongPressGestureRecognizer(target: self, action: Selector("handleLongPress:"))
    longTapRecognizer.minimumPressDuration = 0.2
    view!.addGestureRecognizer(longTapRecognizer)

}

These are the functions that handle the gestures:

func handleTap(recognizer: UIGestureRecognizer) {
    //currently all handled in touchesBegan
}

func handleLongPress(recognizer: UIGestureRecognizer) {
    print("1 --------> longPress Called.... ", recognizer.state.rawValue, gameState)
    if gameState == .Play {
       //do stuff
       //duck Hero
    } else {
       //switch gameState
    }
}

This is the function that handles the touches/taps:

override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
   /* Called when a touch begins */

for touch in touches {
     let location = touch.locationInNode(self)

     //do stuff

     switch gameState {
        case .MainMenu:
        break
        ... //more states
        }
   }
   super.touchesBegan(touches, withEvent: event)
}

If I move everything from touchesBegans to a tapRecogniser (the empty function above), I have to implement this too, to convert the touch location coordinates:

func handleTap(recognizer: UIGestureRecognizer) {
    let location = convertPointFromView(CGPoint(x: recognizer.locationInView(nil).x, y: recognizer.locationInView(nil).y))
    print("Converted Coords: ", location)

    //then do all touchesBegan stuff
 }

I've tried both, but the latter seems realllllly slow and sluggish. Maybe I'm forgetting to implement something that is recommended?

Seems my longPress gesture doesn't always get called, could there be some conflict between these?


Solution

  • so if you hold on the red square for two seconds you'll get a message, when you let go the message disappears. you might have to add some booleans in there to make sure your character isnt repeating some action every frame after the 2 second button hold. this should be enough to get you started hopefully

    import SpriteKit
    
    class GameScene: SKScene {
    
        // time values
        var delta = NSTimeInterval(0)
        var last_update_time = NSTimeInterval(0)
    
        var longTouchTimer = NSTimeInterval(0)
        var touched = false
        var testLabel = SKLabelNode(text: "you have touched for awhile now bro")
    
        let touchSprite = SKSpriteNode(color: SKColor.redColor(), size: CGSizeMake(100, 100))
    
        override func didMoveToView(view: SKView) {
            touchSprite.position = CGPointMake(self.size.width/2, self.size.height/2)
            addChild(touchSprite)
    
            testLabel.hidden = true
            testLabel.position = touchSprite.position
            testLabel.position.y += 100
            testLabel.fontSize = 20
            addChild(testLabel)
        }
    
    
        override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
            for touch: AnyObject in touches {
                let location = touch.locationInNode(self)
    
                if touchSprite.containsPoint(location) {
                    touched = true
                }
            }
        }
    
        override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
            for touch: AnyObject in touches {
                let location = touch.locationInNode(self)
    
                if !touchSprite.containsPoint(location) {
                    touched = false
                    longTouchTimer = 0
                }
            }
        }
    
        override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
            touched = false
            longTouchTimer = 0
        }
    
        override func update(currentTime: NSTimeInterval) {
            if last_update_time == 0.0 {
                delta = 0
            } else {
                delta = currentTime - last_update_time
            }
    
            last_update_time = currentTime
    
            if touched {
                longTouchTimer += delta
            }
    
            if longTouchTimer >= 2 {
                testLabel.hidden = false
            } else {
                testLabel.hidden = true
            }
        }
    }