2015-12-11 18 views
6

私のゲームでSpriteKitでボタンや画像を使ってショップを作成しようとしていますが、スクロールできるアイテムが必要です(UITableViewのように複数のSKSpriteNodesとSKLabelNodes各セルに)。どのように私はSpriteKitでこれを行うことができますか?spritekitで垂直スクロールメニューを作成するには?

+0

ダン上にある、あなたはボタンがCrashoverride777のスクロールビューで作業を取得する方法を見つけ出すのですか?私は問題を抱えています。 –

+0

@JoshSchlabachええ、私はそれがまだスクロールしていると思っていた間にタッチを認識しないので、スクロールビューがスクロールを完了し、静的になることを確認することと覚えているように思います私はそれが時々少しバギーだったので、私はそれを使用していませんでした! – Dan2899

+0

あなたは何を使ったのですか?私のアプリのスクロールビューで助けが必要です! –

答えて

12

2番目の答えは約束通り、私は問題を理解しました。

私はgitHubプロジェクトからこのコードの最新バージョンを入手することをお勧めします。この回答はリンクが最下部にあるため変更しました。

ステップ1:新しい迅速なファイルを作成し、このコードで

import SpriteKit 

/// Scroll direction 
enum ScrollDirection { 
    case vertical // cases start with small letters as I am following Swift 3 guildlines. 
    case horizontal 
} 

class CustomScrollView: UIScrollView { 

// MARK: - Static Properties 

/// Touches allowed 
static var disabledTouches = false 

/// Scroll view 
private static var scrollView: UIScrollView! 

// MARK: - Properties 

/// Current scene 
private let currentScene: SKScene 

/// Moveable node 
private let moveableNode: SKNode 

/// Scroll direction 
private let scrollDirection: ScrollDirection 

/// Touched nodes 
private var nodesTouched = [AnyObject]() 

// MARK: - Init 
init(frame: CGRect, scene: SKScene, moveableNode: SKNode) { 
    self.currentScene = scene 
    self.moveableNode = moveableNode 
    self.scrollDirection = scrollDirection 
    super.init(frame: frame) 

    CustomScrollView.scrollView = self 
    self.frame = frame 
    delegate = self 
    indicatorStyle = .White 
    scrollEnabled = true 
    userInteractionEnabled = true 
    //canCancelContentTouches = false 
    //self.minimumZoomScale = 1 
    //self.maximumZoomScale = 3 

    if scrollDirection == .horizontal { 
     let flip = CGAffineTransformMakeScale(-1,-1) 
     transform = flip 
    } 
} 

required init?(coder aDecoder: NSCoder) { 
    fatalError("init(coder:) has not been implemented") 
    } 
} 

// MARK: - Touches 
extension CustomScrollView { 

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

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

     guard !CustomScrollView.disabledTouches else { return } 

     /// Call touches began in current scene 
     currentScene.touchesBegan(touches, withEvent: event) 

     /// Call touches began in all touched nodes in the current scene 
     nodesTouched = currentScene.nodesAtPoint(location) 
     for node in nodesTouched { 
      node.touchesBegan(touches, withEvent: event) 
     } 
    } 
} 

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

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

     guard !CustomScrollView.disabledTouches else { return } 

     /// Call touches moved in current scene 
     currentScene.touchesMoved(touches, withEvent: event) 

     /// Call touches moved in all touched nodes in the current scene 
     nodesTouched = currentScene.nodesAtPoint(location) 
     for node in nodesTouched { 
      node.touchesMoved(touches, withEvent: event) 
     } 
    } 
} 

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

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

     guard !CustomScrollView.disabledTouches else { return } 

     /// Call touches ended in current scene 
     currentScene.touchesEnded(touches, withEvent: event) 

     /// Call touches ended in all touched nodes in the current scene 
     nodesTouched = currentScene.nodesAtPoint(location) 
     for node in nodesTouched { 
      node.touchesEnded(touches, withEvent: event) 
     } 
    } 
} 

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

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

     guard !CustomScrollView.disabledTouches else { return } 

     /// Call touches cancelled in current scene 
     currentScene.touchesCancelled(touches, withEvent: event) 

     /// Call touches cancelled in all touched nodes in the current scene 
     nodesTouched = currentScene.nodesAtPoint(location) 
     for node in nodesTouched { 
      node.touchesCancelled(touches, withEvent: event) 
     } 
    } 
    } 
} 

// MARK: - Touch Controls 
extension CustomScrollView { 

    /// Disable 
    class func disable() { 
     CustomScrollView.scrollView?.userInteractionEnabled = false 
     CustomScrollView.disabledTouches = true 
    } 

    /// Enable 
    class func enable() { 
     CustomScrollView.scrollView?.userInteractionEnabled = true 
     CustomScrollView.disabledTouches = false 
    } 
} 

// MARK: - Delegates 
extension CustomScrollView: UIScrollViewDelegate { 

    func scrollViewDidScroll(scrollView: UIScrollView) { 

     if scrollDirection == .horizontal { 
      moveableNode.position.x = scrollView.contentOffset.x 
     } else { 
      moveableNode.position.y = scrollView.contentOffset.y 
     } 
    } 
} 

を貼り付ける。これは、UIScrollViewののサブクラスを作成し、それの基本的なプロパティを設定します。それは、関連シーンに渡される独自の触れ方を持つよりも。

ステップ2:あなたはとても

weak var scrollView: CustomScrollView! 
let moveableNode = SKNode() 

のようなスクロールビューと可動ノードのプロパティを作成し、それを使用して

scrollView = CustomScrollView(frame: CGRect(x: 0, y: 0, width: self.frame.size.width, height: self.frame.size.height), scene: self, moveableNode: moveableNode, scrollDirection: .vertical) 
scrollView.contentSize = CGSizeMake(self.frame.size.width, self.frame.size.height * 2) 
view?.addSubview(scrollView) 


addChild(moveableNode) 

didMoveToView

シーンにそれらを追加したいあなたの関連するシーンでは何1行目でこれを行うと、あなたはシーンの大きさとスクロールビューヘルパーを初期化していますか?参照用のシーンとステップ2で作成したmoveableNodeも渡します。 2行目は、scrollViewのコンテンツサイズを設定します。この場合、画面の高さの2倍です。

ステップ3:ラベルやノードなどを追加して配置します。

label1.position.y = CGRectGetMidY(self.frame) - self.frame.size.height 
moveableNode.addChild(label1) 

この例では、ラベルはscrollViewの2ページ目にあります。これは、あなたがラベルやポジショニングをしなければならない場所です。

スクロールビューにたくさんのページがあり、次のことを行うためのラベルがたくさんある場合は、お勧めします。スクロールビューのページごとにSKSpriteNodeを作成し、それぞれに画面のサイズを設定します。 page1Node、page2Nodeなどのように呼び出します。たとえば、2番目のページに必要なすべてのラベルをpage2Nodeに追加するよりも簡単です。ここでの利点は、基本的にはpage2Node内でいつものようにすべての要素を配置できることと、scrollView内にpage2Nodeを配置することだけであるということです。

スクロールビューを縦方向に使用しているため(あなたが望む通り)、反転や逆方向の配置を行う必要はありません。

クラスファンクションをいくつか作成しました。そのため、scrollViewを無効にする必要がある場合は、scrollViewの別のメニューontopをオーバーレイします。

CustomScrollView.enable() 
CustomScrollView.disable() 

最後に、シーンからスクロールビューを削除してから新しいものに切り替えるのを忘れないでください。スプライトキットでUIKitを扱うときの痛みの1つ。水平スクロールする

scrollView?.removeFromSuperView() 

単に(ステップ2).horizo​​ntalするinitメソッドのスクロール方向を変えます。

今や最大の苦痛は、物を配置するときにすべてが逆になっていることです。したがって、スクロールビューは右から左に移動します。したがって、scrollViewの "contentOffset"メソッドを使用して位置を変更し、基本的にすべてのラベルを右から左へ逆順に配置する必要があります。 SkNodesを使用すると、何が起きているのかを理解した後、これをもっと簡単にすることができます。

これは大いに役立ちますが、私が言ったように、スプライトキットの苦痛です。どうしたらいいのか教えてください。

プロジェクトはGitHubの

https://github.com/crashoverride777/SwiftySKScrollView

+0

これは絶対に素晴らしいことです。明日はそれを実装するつもりです。私はそれがどのように進むのかをあなたにお知らせします。そんなにあなたは絶対的な命を救う者ありがとう – Dan2899

+0

あなたは大歓迎です。これは動作するはずです、私はメモリをリフレッシュするための基本テンプレートを使ってxCodeで試しました。私が何かを見逃してしまったかどうかを教えてください。 – crashoverride777

+0

今朝はそれを実装しなければならなかったが、それは夢のように働いていた。本当に巧妙な方法ですが、実際には移動可能なノードを使用し、移動可能なノードにノードを追加することは実際には機能します。もう一度感謝しています - あなたは大規模な助けと素晴らしい仕事をしてきました! – Dan2899

4

あなたは、2つのオプション

1)自由のための効果などをバウンス、あなたは、このような勢いは、スクロールなど、物事を得るよう、これは、ページングよりよい解決策である道UIScrollViewの

を使用しています。しかし、多くのUIKitを使用するか、SKSpritenodeやラベルを使用するためにいくつかのサブクラスを作成する必要があります。

例えば

https://github.com/crashoverride777/SwiftySKScrollView

2をgithubの上の私のプロジェクトをチェックしてください)使用SpriteKitベース

あなたdidMoveToViewを設定
Declare 3 class variables outside of functions(under where it says 'classname': SKScene): 
var startY: CGFloat = 0.0 
var lastY: CGFloat = 0.0 
var moveableArea = SKNode() 

、シーンにSKNodeを追加し、2つのラベル、のための1つを追加トップとボトムが1つになっています。次に、あなたのタッチを設定

override func didMoveToView(view: SKView) { 
    // set position & add scrolling/moveable node to screen 
    moveableArea.position = CGPointMake(0, 0) 
    self.addChild(moveableArea) 

    // Create Label node and add it to the scrolling node to see it 
    let top = SKLabelNode(fontNamed: "Avenir-Black") 
    top.text = "Top" 
    top.fontSize = CGRectGetMaxY(self.frame)/15 
    top.position = CGPoint(x:CGRectGetMidX(self.frame), y:CGRectGetMaxY(self.frame)*0.9) 
    moveableArea.addChild(top) 

    let bottom = SKLabelNode(fontNamed: "Avenir-Black") 
    bottom.text = "Bottom" 
    bottom.fontSize = CGRectGetMaxY(self.frame)/20 
    bottom.position = CGPoint(x:CGRectGetMidX(self.frame), y:0-CGRectGetMaxY(self.frame)*0.5) 
    moveableArea.addChild(bottom) 
} 

はあなたの最初のタッチの位置を保存するために始めた:その後

override func touchesBegan(touches: NSSet, withEvent event: UIEvent) { 
    // store the starting position of the touch 
    let touch: AnyObject? = touches.anyObject(); 
    let location = touch?.locationInNode(self) 
    startY = location!.y 
    lastY = location!.y 
} 

はタッチが高速で、設定された制限にしてノードをスクロールするには、次のコードで移動セットアップセット:

override func touchesMoved(touches: NSSet, withEvent event: UIEvent) { 
    let touch: AnyObject? = touches.anyObject(); 
    let location = touch?.locationInNode(self) 
    // set the new location of touch 
    var currentY = location!.y 

    // Set Top and Bottom scroll distances, measured in screenlengths 
    var topLimit:CGFloat = 0.0 
    var bottomLimit:CGFloat = 0.6 

    // Set scrolling speed - Higher number is faster speed 
    var scrollSpeed:CGFloat = 1.0 

    // calculate distance moved since last touch registered and add it to current position 
    var newY = moveableArea.position.y + ((currentY - lastY)*scrollSpeed) 

    // perform checks to see if new position will be over the limits, otherwise set as new position 
    if newY < self.size.height*(-topLimit) { 
     moveableArea.position = CGPointMake(moveableArea.position.x, self.size.height*(-topLimit)) 
    } 
    else if newY > self.size.height*bottomLimit { 
     moveableArea.position = CGPointMake(moveableArea.position.x, self.size.height*bottomLimit) 
    } 
    else { 
     moveableArea.position = CGPointMake(moveableArea.position.x, newY) 
    } 

    // Set new last location for next time 
    lastY = currentY 
} 

すべてのクレジットは、この記事

に行きます

+0

ありがとう、本当に便利です!このメソッドはUIScrollViewに付属する慣性を許可しますか?それとも自分で追加しなければならないのでしょうか? – Dan2899

+0

あなたは残念なことにクールな効果を得ることはありません。スクロールビューでは、スケッチで使用するのはそんなに苦痛です。 UIKitオブジェクトの代わりにSKNodeを追加するには、タッチ登録をトリッキーにしなければなりません。スクロールビューの上にメニューをオーバーレイするときに無効にする必要があります。スクロールビューを反転しない限り、 SpriteKitキットはUKitとは異なる座標を持っているため、別の場所に配置する必要があります。それはかなり混乱ですが、それは実行可能です。メニューがあなたにとってどれほど重要かによって異なります – crashoverride777

+0

これまでのお勧めの方法のように見えます。私はなぜSpriteKitのScrollViewに関するドキュメンテーションが少ないのかと疑問に思いました。 – Dan2899

関連する問題