我正在寻找在我的游戏中创建一个商店(在SpriteKit中)的按钮和图像,但我需要的项目是可以滚动的,所以玩家可以上下滚动商店(就像一个UITableView,但有多个SKSpriteNodes和SKLabelNodes在每个单元格中)。任何想法如何我可以在SpriteKit中做到这一点?如何在spritekit中创建一个垂直滚动菜单?
回答
第二个答案如所承诺的,我刚才发现了这个问题。
我建议始终从我的gitHub项目中获取此代码的最新版本incase我做了更改,因为此答案,链接位于底部。
第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的子类,并建立了它的基本属性粘贴。它比自己的触摸方法传递到相关的场景。
第二步:在您的相关场景,你想用它创建一个滚动视图和可移动节点属性,像这样
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的第2页。这是你不得不随身携带标签和定位的地方。
我建议如果你在滚动视图中有很多页面并且有很多标签要做以下操作。在滚动视图中为每个页面创建一个SKSpriteNode,并使它们都成为屏幕的大小。将它们称为page1Node,page2Node等。然后将所需的所有标签添加到page2Node中。这样做的好处是,你基本上可以像往常一样在page2Node中定位所有的东西,而不仅仅是在scrollView中定位page2Node。
你也很幸运,因为使用垂直scrollView(你说你想要的),你不需要做任何翻转和反向定位。
我做了一些类的func,所以如果你需要禁用你的scrollView incase你覆盖scrollView的顶部的另一个菜单。
CustomScrollView.enable()
CustomScrollView.disable()
最后别忘过渡到一个新的之前删除从场景中的滚动视图。在spritekit中处理UIKit时的一个难题。
scrollView?.removeFromSuperView()
对于水平滚动,只需将init方法的滚动方向更改为.horizontal(步骤2)即可。
现在最大的痛苦就是在定位东西时一切都反过来。所以滚动视图从右到左。因此,您需要使用scrollView“contentOffset”方法重新定位它,并且基本上将所有标签以相反的顺序从右到左排列。一旦你明白发生了什么,再次使用SkNodes使得这更容易。
希望这有助于并为大量的帖子感到抱歉,但正如我所说的那样,spritekit有点痛苦。让我知道它是如何去的,如果我错过了任何东西。
项目在GitHub上
这真是太神奇了,我明天就会着手实施它,我会告诉你它是如何发生的。谢谢你,你是一个绝对的救星 – Dan2899
不客气。这应该defo的工作,我只是用xCode与基本模板来刷新我的记忆。请让我知道它是如何去只是因为我错过了什么。 – crashoverride777
今天早上去实施它,它的工作就像一个梦。一个非常聪明的方法,实际上,使用可移动节点并将节点添加到可移动节点真的起作用。再次非常感谢 - 您一直在为我们提供大量帮助,并做出了卓越的工作 – Dan2899
您有2个选项
1)使用一个UIScrollView
下山的路,这是更好的解决方案,你得到的东西,如势头滚动,分页,反弹免费的效果等。然而,你必须使用很多UIKit的东西,或者做一些子类来使它与SKSpritenodes或标签一起工作。
检查我在GitHub上的项目为例
https://github.com/crashoverride777/SwiftySKScrollView
2)使用SpriteKit
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()
设置您didMoveToView的SKNode添加到场景中,并添加2个标签,一个是顶部和底部看到它的工作!
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
}
一切归功于这篇文章
http://greenwolfdevelopment.blogspot.co.uk/2014/11/scrolling-in-sprite-kit-swift.html
Thankyou真的很有用!此方法是否允许UIScrollView附带的惯性?或者我必须尝试自己补充一下? – Dan2899
不幸的是,你不会得到很酷的效果。使用滚动视图在skscenes中使用是一件很痛苦的事情。你必须做一些欺骗手段来注册触摸,添加SKNode而不是UIKit对象,当你在滚动视图顶部叠加菜单时必须停用它,除非你翻动滚动视图,否则事物将以相反的方向滚动,你必须以不同的方式定位不同的东西,因为SpriteKit套件与UKit具有不同的坐标。这是相当混乱的,但它是可行的。取决于菜单对你有多重要 – crashoverride777
看起来你以前推荐的方法就是这样的答案!我想知道为什么SpriteView在SpriteKit上的文档太少... – Dan2899
- 1. 创建一个垂直快速滚动菜单web
- 2. 垂直滚动菜单
- 3. 创建垂直菜单
- 4. 创建垂直菜单
- 5. 如何在Joomla中创建单页垂直滚动网站
- 6. 垂直菜单/导航自动滚动
- 7. 如何创建一个垂直导航菜单?
- 8. 如何创建一个垂直下拉菜单
- 9. 在Wpf中创建一个垂直菜单
- 10. 如何在Cocos2D-iPhone 2.1中显示垂直滚动菜单?
- 11. ASP.Net垂直菜单与滚动功能
- 12. 如何避免垂直下拉菜单在底部添加垂直滚动条?
- 13. iOS 7 SpriteKit滚动菜单?
- 14. 在下拉菜单中创建水平和垂直菜单
- 15. 创建一个水平滚动菜单
- 16. 如何在WPF中创建垂直菜单控件
- 17. 在图像旁创建一个垂直菜单
- 18. 如何在dijit菜单上放置垂直滚动条
- 19. 如何添加垂直滚动条到滑动菜单
- 20. 创建垂直菜单像www.tokonita.com
- 21. 使用css创建垂直菜单
- 22. 创建垂直选项卡菜单
- 23. 如何创建滚动的菜单? CSS
- 24. 在android的布局中创建2个垂直滚动条
- 25. 需要帮助创建一个垂直图像精灵菜单
- 26. 如何设计一个长下拉菜单的垂直菜单?
- 27. 如何滑动垂直菜单jQuery?
- 28. 如何使长Bootstrap下拉菜单可垂直滚动?
- 29. 在Xcode中创建一个暂停菜单SpriteKit
- 30. 如何使用vb.net中的下拉菜单创建垂直菜单栏
丹,你有没有弄清楚如何获得与Crashoverride777的滚动视图工作的按钮?我遇到了麻烦 –
@JoshSchlabach是的我做了,我似乎记得这是为了确保滚动视图完成滚动并变为静态,因为它不会识别触摸,但它认为它仍在滚动,尽管有时候我发现它有点bug,所以我最终没有使用它! – Dan2899
那你用了什么?我需要我的应用程序的滚动视图帮助! –