2014-12-03 3 views
0

У меня есть SKScene с кучей узлов (SKSpriteNode с, SKShapeNode с, и т.д.), что я хотел бы иметь возможность панорамирования по отдельности и одновременно. Мне нужно уметь:Несколько панорамирование жесты в SpriteKit сцене

  • Прикоснитесь к одному узлу и переместите его вокруг.
  • При перемещении одного узла коснитесь нескольких других узлов и перемещайте их.

Если бы я мог добавить UIPanGestureRecognizer для каждого узла, это было бы легко. Но, насколько я могу судить, мой единственный вариант с UIGestureRecognizer заключается в том, чтобы добавить его в viewSKScene. Я реализовал это с помощью одного распознавателя, и жонглирование всеми касаниями и узлами связанного с распознаванием действия на моем SKScene было немного больно. Вот что я сделал для распознавателя:

class MultiplePanGestureRecognizer: UIGestureRecognizer { 

    var currentTouches: Array<UITouch> = [] 

    override func touchesBegan(touches: NSSet!, withEvent event: UIEvent!) { 

     super.touchesBegan(touches, withEvent: event) 

     for touch in touches { 
      currentTouches.append(touch as UITouch) 
     } 

     state = .Began 
    } 

    override func touchesMoved(touches: NSSet!, withEvent event: UIEvent!) { 

     super.touchesMoved(touches, withEvent: event) 

     state = .Changed 
    } 

    override func touchesEnded(touches: NSSet!, withEvent event: UIEvent!) { 

     super.touchesEnded(touches, withEvent: event) 

     removeCancelledOrEndedTouches(touches) 
    } 

    override func touchesCancelled(touches: NSSet!, withEvent event: UIEvent!) { 

     super.touchesCancelled(touches, withEvent: event) 

     removeCancelledOrEndedTouches(touches) 
    } 

    // Add new touches to currentTouches 
    func addUntrackedTouchesFromSet(touches: NSSet!) { 

     for touch in touches { 

      let index = find(currentTouches, touch as UITouch) 

      if index == nil { 

       currentTouches.append(touch as UITouch) 
      } 
     } 
    } 

    // Remove received touches from currentTouches array 
    func removeCancelledOrEndedTouches(touches: NSSet!) { 

     for touch in touches { 
      if let index = find(currentTouches, touch as UITouch) { 
       currentTouches.removeAtIndex(index) 
      } 
     } 

     // End the gesture if there are no touches remaining in currentTouches 
     if currentTouches.count == 0 { 
      state = .Ended 
     } 
    } 

    override func reset() { 

     super.reset() 

     currentTouches = [] 
    } 
} 

В принципе, я просто держать все штрихи доступны на currentTouches свойство жест распознаватель, так что я могу получить доступ все их в прикрепленном действии. Это означает, что я должен манипулировать тем, что касается ударов узлов и т. Д., В SKScene. Первоначально я попытался перезапустить жест, установив его состояние на .Began в touchesBegan:withEvent: распознавателя жестов. Однако ручной сброс состояния распознавателя на .Began не вызвал действие, поэтому я был вынужден разрешить новые касания в состоянии .Changed в моем распознавателе, а затем жонглировать всем в действии.

Для справки, вот метод в моем SKScene, который добавляется в качестве действия распознаватель в: (. touchNodeMap является просто Dictionary, который отображает UITouch эс в SKNode с)

func handleMultiplePan(recognizer: MultiplePanGestureRecognizer) { 

    switch recognizer.state { 
    case .Began, .Changed: 

     // Remove those touches from tracking that are no longer being 
     // recognized 
     touchNodeMap.prune(recognizer.currentTouches) 

     // Iterate over the recognizer's currentTouches 
     for touch in recognizer.currentTouches { 

      // Is it over a child node of the scene? 
      if let node = getChildNodeForTouch(touch) { 

       // If so, add it to the touchNodeMap 
       touchNodeMap.add(touch, withNode: node) 
      } 
     } 

     // Iterate over currentlyPanningTouches and move nodes accordingly 
     for (touch, node) in touchNodeMap { 

      let location = touch.locationInNode(self) 
      let previousLocation = touch.previousLocationInNode(self) 
      let deltaX = location.x - previousLocation.x 
      let deltaY = location.y - previousLocation.y 
      node.position = CGPointMake(node.position.x + deltaX, node.position.y + deltaY) 
     } 

     // Get node for most recent touch 
     let (_, mostRecentNode) = touchNodeMap.mostRecentTouchAndNode() 

     // Remove and re-add it to the scene 
     if mostRecentNode != nil { 
      mostRecentNode!.removeFromParent() 
      addChild(mostRecentNode!) 
     } 

    default: 
     break 
    } 
} 

Мой вопрос , я что-то упустил? Есть ли способ использовать UIGestureRecognizer с по каждому узлу? Или, есть ли лучший способ сделать то, что я пытаюсь сделать?

+0

Вы видели [учебник] (http://www.raywenderlich.com/44270/sprite-kit-tutorial-how-to-drag-and-drop-sprites) на сайте Рэя Вендерлиха? Похоже, это отличное место для начала. – Moshe

+0

@Moshe, по моему вопросу, мне нужно иметь возможность перемещать * несколько * узлов * одновременно *. – GarlicFries

ответ

0

У меня был такой же вызов, и у меня действительно была хорошая помощь от @vacawama. Plesae см. Эту ссылку: How to implement multiple PanGestures (Draggable views)?

Я этот, что вы ищете?

+0

Я ценю ответ, @Kjetil, но нет, у вас не было той же проблемы. Вы хотели манипулировать несколькими 'UIView', а не несколькими дочерними узлами 'SKScene'. – GarlicFries

+0

что об этом: [link] (http://asmeurer.github.io/blog/posts/playing-with-swift-and-spritekit/)? – Kjetil

+0

Это ближе, @ Kjetil, но все же не то, что мне нужно. Я собираюсь справиться с множеством жестов, и сброс всей этой логики в методы обработки сенсорных данных SKScene превратятся в беспорядок очень быстро. Это часть того, чего я хочу избежать. – GarlicFries

Смежные вопросы