Reanimation
Reanimation

Reputation: 3336

Swift Game - Tap and Tap + Hold Gestures?

I'm in the process of learning swift (and spritekit) and trying to make a simple game.

In my game, the hero should jump or duck...

The hero needs to jump when the screen is tapped,or duck if the screen is tap+held (long gesture)

So basic pseudo code:

if tapped
    heroJump()
else if tappedAndHeld
    heroDuck()

I have a func which is seen in almost all tutorials, which handles the touch event:

override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {

for touch in touches {
let location = touch.locationInNode(self) //need location of tap for something

    switch gameState {
        case .Play:
            //do in game stuff

            break
        case .GameOver:
            //opps game ended

            }
            break
    } 
 }
   super.touchesBegan(touches, withEvent: event)
}

Is there a way, to include in this touch event, to decide if it was tapped or held? I can't seem to get my head around the fact, the program will always recognise a tap before a long gesture?!?

Anyway, in an attempt to solve my problem, I found THIS question, which introduced to me recognisers, which I tried to implement:

override func didMoveToView(view: SKView) {
    // other stuff

    //add long press gesture, set to start after 0.2 seconds
    let longPressRecognizer = UILongPressGestureRecognizer(target: self, action: "longPressed:")
    longPressRecognizer.minimumPressDuration = 0.2
    self.view!.addGestureRecognizer(longPressRecognizer)

    //add tap gesture
    let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: "tapped:")
    self.view!.addGestureRecognizer(tapGestureRecognizer)
}

And these are the functions the gestures call:

func longPressed(sender: UILongPressGestureRecognizer)
{
    if (sender.state == UIGestureRecognizerState.Ended) {
        print("no longer pressing...")
    } else if (sender.state == UIGestureRecognizerState.Began) {
        print("started pressing")
        // heroDuck()
    }
}

func tapped(sender: UITapGestureRecognizer)
{
    print("tapped")
    // heroJump()
}

How can I combine these two things? Can I add a way to determine whether it was tapped or hold in my touchBegins event, or can I scrap that method and use only the two functions above?

One of many problems being getting the location if using the latter?

Or maybe I'm looking at this completely wrong, and there's a simple and/or built in way in swift/spritekit?

Thanks.

Upvotes: 2

Views: 2261

Answers (2)

joern
joern

Reputation: 27620

You only need the UITapGestureRecognizer and the UILongPressRecognizer. You do not need to do anything with touchesBegan and touchesEnded, because the gesture recognizer analyses the touches itself.

To get the location of the touch you can call locationInView on the gesture recognizer to get the location of the gesture or locationOfTouch if you are working with multitouch gestures and need the location of each touch. Pass nil as parameter when you want the coordinates in the window’s base coordinate system.

Here is a working example:

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

func handleLongPress(recognizer: UIGestureRecognizer) {
    if recognizer.state == .Began {
        print("Duck! (location: \(recognizer.locationInView(nil))")
    }
}

func handleTap(recognizer: UIGestureRecognizer) {
    print("Jump! (location: \(recognizer.locationInView(nil))")
}

If a long press is recognized handleTap: tap is not called. Only if the user lifts his finger fast enough handleTap: will be called. Otherwise handleLongPress will be called. handleLongPress will only be called after the long press duration has passed. Then handleLongPress will be called twice: When the duration has passed ("Began") and after the user has lifted his finger ("Ended").

Upvotes: 6

Knight0fDragon
Knight0fDragon

Reputation: 16827

you do the same thing you are doing for longpress, wait till the .Ended event

func tapped(sender: UITapGestureRecognizer)
{

    if sender.state == .Ended {
      print("tapped")
    }
}

A tap event will always happen, this can't be prevented because lets face it, you need to touch the screen. What should be happening though is when you enter the long press event, the tap event should go into a Cancel state instead of an Ended state

Upvotes: 0

Related Questions