我希望在游戏中(SpriteKit)中创建带有按钮和图像的商店,但我需要使这些物品能够滚动,以便玩家可以上下滚动商店(就像UITableView一样,但每个商店中都有多个SKSpriteNodes和SKLabelNodes细胞)。知道如何在SpriteKit中做到这一点吗?
正如所答应的第二个答案,我只是想出了问题。
我建议始终从gitHub项目中获取此代码的最新版本,以防由于此答案以来我进行了更改,链接位于底部。
第1步:创建一个新的swift文件并粘贴此代码
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()
并将它们添加到didMoveToView中的场景中
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)
您在第1行中所做的就是使用场景尺寸初始化滚动视图帮助器。您还将传递场景作为参考,并传递在步骤2中创建的moveableNode。第2行是您设置scrollView内容大小的地方,在这种情况下,它是屏幕高度的两倍。
第3步:-添加标签或节点等并放置它们。
label1.position.y = CGRectGetMidY(self.frame) - self.frame.size.height moveableNode.addChild(label1)
在此示例中,标签将位于scrollView的第二页上。这是您必须摆弄标签和位置的地方。
我建议如果滚动视图中有很多页面,并且有很多标签,请执行以下操作。为滚动视图中的每个页面创建一个SKSpriteNode,并使每个页面的大小与屏幕大小相同。称它们为page1Node,page2Node等。然后将您想要的所有标签(例如,第二页上的所有标签)添加到page2Node。这样做的好处是,您基本上可以像往常一样将所有内容放置在page2Node中,而不仅仅是将page2Node放置在scrollView中。
您也很幸运,因为垂直使用scrollView(您说您想要的)不需要进行任何翻转和反向定位。
我做了一些类功能,所以如果您需要禁用scrollView的话,以防您在scrollView顶部覆盖了另一个菜单。
CustomScrollView.enable() CustomScrollView.disable()
最后,不要忘记在过渡到新场景之前从场景中删除滚动视图。在spritekit中处理UIKit时的痛苦之一。
scrollView?.removeFromSuperView()
对于水平滚动,只需将init方法上的滚动方向更改为.horizontal(步骤2)。
而现在最大的痛苦是,在放置东西时一切都是相反的。因此,滚动视图从右到左。因此,您需要使用scrollView“ contentOffset”方法重新定位它,并且基本上将所有标签从右到左以相反的顺序放置。一旦了解发生了什么,再次使用SkNodes将使此操作变得更加容易。
希望这会有所帮助,并为大量的帖子感到抱歉,但是正如我所说,spritekit有点痛苦。让我知道进展如何,如果我错过了任何事情。
项目在gitHub上
https://github.com/crashoverride777/SwiftySKScrollView