【问题标题】:How can I make my level menu scrollable vertically?如何使我的关卡菜单可以垂直滚动?
【发布时间】:2017-03-28 14:40:28
【问题描述】:

我有以下级别的菜单(如下所示)。我想让它垂直滚动,从而使总高度是屏幕的两倍(完全滚动高度)。我怎样才能做到这一点?

下面是上图的代码:

class LevelMenu: SKScene {


let levelButtonSize = SKSpriteNode(imageNamed: "b1").size
let levelButton1: SKSpriteNode = SKSpriteNode(imageNamed: "b1")

let levelButton2: SKSpriteNode = SKSpriteNode(imageNamed: "b2")
let levelButton3: SKSpriteNode = SKSpriteNode(imageNamed: "b3")
let levelButton4: SKSpriteNode = SKSpriteNode(imageNamed: "b4")
let levelButton5: SKSpriteNode = SKSpriteNode(imageNamed: "b5")
let levelButton6: SKSpriteNode = SKSpriteNode(imageNamed: "b6")
let levelButton7: SKSpriteNode = SKSpriteNode(imageNamed: "b7")
let levelButton8: SKSpriteNode = SKSpriteNode(imageNamed: "b8")

let levelButton9: SKSpriteNode = SKSpriteNode(imageNamed: "b9")
let levelButton10: SKSpriteNode = SKSpriteNode(imageNamed: "b10")
let levelButton11: SKSpriteNode = SKSpriteNode(imageNamed: "b11")
let levelButton12: SKSpriteNode = SKSpriteNode(imageNamed: "b12")

override init(size: CGSize){
    super.init(size: size)
    let bg = SKSpriteNode(imageNamed: "bg")
    backgroundImage.position = CGPoint(x: self.frame.midX, y: self.frame.midY)
    self.addChild(bg)

    let column1PosX = levelButtonSize.width*cDiff
    let column2PosX = levelButtonSize.width*cDiff + levelButtonSize.width*2.0
    let column3PosX = levelButtonSize.width*cDiff + levelButtonSize.width*4.0

    let row1PosY = self.frame.height - levelButtonSize.width*1.5
    let row2PosY = row1PosY - levelButtonSize.height - levelButtonSize.width*rDiff
    let row3PosY = row2PosY - levelButtonSize.height - levelButtonSize.width*rDiff
    let row4PosY = row3PosY - levelButtonSize.height - levelButtonSize.width*rDiff

    levelButton1.position = CGPoint(x: column1PosX, y:  row1PosY)
    levelButton1.zPosition = 10
    self.addChild(levelButton1)


    levelButton2.position = CGPoint(x: column2PosX, y:  row1PosY)
    self.addChild(levelButton2)

    levelButton3.position = CGPoint(x: column3PosX, y:  row1PosY)
    self.addChild(levelButton3)

    levelButton4.position = CGPoint(x: column1PosX, y: row2PosY)
    self.addChild(levelButton4)

    levelButton5.position = CGPoint(x: column2PosX, y: row2PosY)
    self.addChild(levelButton5)

    levelButton6.position = CGPoint(x: column3PosX, y: row2PosY)
    self.addChild(levelButton6)

    levelButton7.position = CGPoint(x: column1PosX, y: row3PosY)
    self.addChild(levelButton7)


    levelButton8.position = CGPoint(x: column2PosX, y: row3PosY)
    self.addChild(levelButton8)


    levelButton9.position = CGPoint(x: column3PosX, y: row3PosY)
    self.addChild(levelButton9)

    levelButton10.position = CGPoint(x: column1PosX, y: row4PosY)
    self.addChild(levelButton10)

    levelButton11.position = CGPoint(x: column2PosX, y: row4PosY)
    self.addChild(levelButton11)

    levelButton12.position = CGPoint(x: column3PosX, y: row4PosY)
    self.addChild(levelButton12)

}

更新

基于 Ron Myschuk 的解决方案,下面的代码显示了我已经能够实现的目标,this link 显示了我目前遇到的问题的 .gif,其中屏幕在菜单顶部滚动过多。

class LMScene: SKScene {

let levelButtonSize = SKSpriteNode(imageNamed: "b1").size
let levelButton1: SKSpriteNode = SKSpriteNode(imageNamed: "b1")

let levelButton2: SKSpriteNode = SKSpriteNode(imageNamed: "b2")
let levelButton3: SKSpriteNode = SKSpriteNode(imageNamed: "b3")
let levelButton4: SKSpriteNode = SKSpriteNode(imageNamed: "b4")
let levelButton5: SKSpriteNode = SKSpriteNode(imageNamed: "b5")
let levelButton6: SKSpriteNode = SKSpriteNode(imageNamed: "b6")
let levelButton7: SKSpriteNode = SKSpriteNode(imageNamed: "b7")
let levelButton8: SKSpriteNode = SKSpriteNode(imageNamed: "b8")

let levelButton9: SKSpriteNode = SKSpriteNode(imageNamed: "b9")
let levelButton10: SKSpriteNode = SKSpriteNode(imageNamed: "b10")
let levelButton11: SKSpriteNode = SKSpriteNode(imageNamed: "b11")
let levelButton12: SKSpriteNode = SKSpriteNode(imageNamed: "b12")

let levelButton13: SKSpriteNode = SKSpriteNode(imageNamed: "b13")
let levelButton14: SKSpriteNode = SKSpriteNode(imageNamed: "b14")
let levelButton15: SKSpriteNode = SKSpriteNode(imageNamed: "b15")
let levelButton16: SKSpriteNode = SKSpriteNode(imageNamed: "b16")
let levelButton17: SKSpriteNode = SKSpriteNode(imageNamed: "b17")
let levelButton18: SKSpriteNode = SKSpriteNode(imageNamed: "b18")


private var scrollCell = SKSpriteNode()

private var moveAmtX: CGFloat = 0
private var moveAmtY: CGFloat = 0
private let minimum_detect_distance: CGFloat = 30
private var initialPosition: CGPoint = CGPoint.zero
private var initialTouch: CGPoint = CGPoint.zero
private var resettingSlider = false

override init(size: CGSize){
    super.init(size: size)


    scrollCell = SKSpriteNode(color: .blue, size: CGSize(width: self.size.width, height: 2*self.size.height - self.frame.width*0.24734))
    scrollCell.position = CGPoint(x: 0, y: 0)
    scrollCell.anchorPoint = CGPoint.zero
    scrollCell.zPosition = 0
    self.addChild(scrollCell)

    let backgroundImage = SKSpriteNode(imageNamed: "bg")
    backgroundImage.position = CGPoint(x: self.frame.midX, y: self.frame.midY)
    self.addChild(backgroundImage)

    let column1PosX = levelButtonSize.width/2 + self.frame.width*0.14855
    let column2PosX = 3*levelButtonSize.width/2 + 2*self.frame.width*0.14855
    let column3PosX = 5*levelButtonSize.width/2 + 3*self.frame.width*0.14855


    let row1PosY = self.frame.height - levelButtonSize.height/2 - self.frame.width*0.24734
    let row2PosY = row1PosY - levelButtonSize.height - self.frame.width*0.24734
    let row3PosY = row2PosY - levelButtonSize.height - self.frame.width*0.24734
    let row4PosY = row3PosY - levelButtonSize.height - self.frame.width*0.24734
    let row5PosY = row4PosY - levelButtonSize.height - self.frame.width*0.24734
    let row6PosY = row5PosY - levelButtonSize.height - self.frame.width*0.24734

    levelButton1.position = CGPoint(x: column1PosX, y:  row1PosY)
    levelButton1.zPosition = 10
    scrollCell.addChild(levelButton1)


    levelButton2.position = CGPoint(x: column2PosX, y:  row1PosY)
    levelButton2.zPosition = 10
    scrollCell.addChild(levelButton2)

    levelButton3.position = CGPoint(x: column3PosX, y:  row1PosY)
    levelButton3.zPosition = 10
    scrollCell.addChild(levelButton3)

    levelButton4.position = CGPoint(x: column1PosX, y: row2PosY)
    levelButton4.zPosition = 10
    scrollCell.addChild(levelButton4)

    levelButton5.position = CGPoint(x: column2PosX, y: row2PosY)
    levelButton5.zPosition = 10
    scrollCell.addChild(levelButton5)

    levelButton6.position = CGPoint(x: column3PosX, y: row2PosY)
    levelButton6.zPosition = 10
    scrollCell.addChild(levelButton6)

    levelButton7.position = CGPoint(x: column1PosX, y: row3PosY)
    levelButton7.zPosition = 10
    scrollCell.addChild(levelButton7)


    levelButton8.position = CGPoint(x: column2PosX, y: row3PosY)
    levelButton8.zPosition = 10
    scrollCell.addChild(levelButton8)

    levelButton9.position = CGPoint(x: column3PosX, y: row3PosY)
    levelButton9.zPosition = 10
    scrollCell.addChild(levelButton9)

    levelButton10.position = CGPoint(x: column1PosX, y: row4PosY)
    levelButton10.zPosition = 10
    scrollCell.addChild(levelButton10)

    levelButton11.position = CGPoint(x: column2PosX, y: row4PosY)
    levelButton11.zPosition = 10
    scrollCell.addChild(levelButton11)

    levelButton12.position = CGPoint(x: column3PosX, y: row4PosY)
    levelButton12.zPosition = 10
    scrollCell.addChild(levelButton12)

    levelButton13.position = CGPoint(x: column1PosX, y: row5PosY)
    levelButton13.zPosition = 10
    scrollCell.addChild(levelButton13)

    levelButton14.position = CGPoint(x: column2PosX, y: row5PosY)
    levelButton14.zPosition = 10
    scrollCell.addChild(levelButton14)

    levelButton15.position = CGPoint(x: column3PosX, y: row5PosY)
    levelButton15.zPosition = 10
    scrollCell.addChild(levelButton15)

    levelButton16.position = CGPoint(x: column1PosX, y: row6PosY)
    levelButton16.zPosition = 10
    scrollCell.addChild(levelButton16)

    levelButton17.position = CGPoint(x: column2PosX, y: row6PosY)
    levelButton17.zPosition = 10
    scrollCell.addChild(levelButton17)

    levelButton18.position = CGPoint(x: column3PosX, y: row6PosY)
    levelButton18.zPosition = 10
    scrollCell.addChild(levelButton18)

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

    if let touch = touches.first as UITouch! {

        if let touch = touches.first as UITouch! {

            self.scrollCell.removeAllActions()
            initialTouch = touch.location(in: self.scene!.view)
            moveAmtY = 0
            initialPosition = self.scrollCell.position
        }
    }

}

override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {

    if let touch = touches.first as UITouch! {

        let movingPoint: CGPoint = touch.location(in: self.scene!.view)

        moveAmtY = movingPoint.y - initialTouch.y

        scrollCell.position = CGPoint(x: initialPosition.x, y: initialPosition.y - moveAmtY)
    }
}

override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {

    checkForResettingSlider()
    yMoveActions(moveTo: -moveAmtY)
}

func checkForResettingSlider() {

    if resettingSlider { return }

    let scrollDif: CGFloat = (scrollCell.size.height - self.size.height) / 2.0

    if scrollCell.position.y > scrollDif {

        let move: SKAction = SKAction.moveTo(y: scrollDif, duration: 0.3)
        move.timingMode = .easeOut
        scrollCell.run(move, completion: { self.resettingSlider = false })
    }

    if scrollCell.position.y < -scrollDif {

        let move: SKAction = SKAction.moveTo(y: 0 - scrollDif, duration: 0.3)
        move.timingMode = .easeOut
        scrollCell.run(move, completion: { self.resettingSlider = false })
    }
}

func yMoveActions(moveTo: CGFloat) {

    let move: SKAction = SKAction.moveBy(x: 0, y: (moveTo * 1.5), duration: 0.3)
    move.timingMode = .easeOut

    self.scrollCell.run(move, completion: { self.checkForResettingSlider() })
}

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

}

【问题讨论】:

  • 您熟悉使用场景相机吗?
  • @TheValyreanGroup 对你发表 7 字的“流行语”评论感到羞耻,没有解释或说明如何使用它或去哪里!
  • @ItsMeAgain 为您发布一个没有任何证据或迹象表明您实际上试图自己解决这个问题的问题感到羞耻。仅 SO 就有数十个示例说明了如何做到这一点!
  • @RonMyschuk 这只是 OP 的一个问题。他可能只需要提醒 SKCamera 就在那里。如果他不知道它是什么或如何使用它,那么他可以回复,我会发布答案。
  • @TheValyreanGroup 很抱歉没有早点回复。我不太熟悉 SKCamera 我愿意使用这种方法

标签: swift swift3 sprite-kit


【解决方案1】:

这是我用来垂直滚动的一些代码,我已经对其进行了调整以适应您的菜单。它并不完全符合你的所有项目,但它会给你一个开始的地方。它会告诉你如何自己解决这个问题。

编辑:我已经更新了代码,改为使用这些资金。仍然以相同的方式声明您的按钮,但调用我的 createMenu 函数来实际创建菜单。它是循环的,因此如果您更改菜单项的数量,它会自动调整。您唯一需要注意的是;如果添加或删除按钮,则相应地更改 createMenu 顶部的数组。还将填充变量调整为您想要的项目之间的垂直空间

func createMenu() {

    let buttons = [levelButton1, levelButton2, levelButton3, levelButton4, levelButton5, levelButton6, levelButton7, levelButton8, levelButton9, levelButton10, levelButton11, levelButton12, levelButton13, levelButton14, levelButton15, levelButton16, levelButton17, levelButton18]
    let padding: CGFloat = 400

    let numberOfRows = CGFloat(buttons.count / 3)

    scrollCell = SKSpriteNode(color: .blue, size: CGSize(width: 1024, height: levelButtonSize.height * numberOfRows + padding * numberOfRows))
    scrollCell.position = CGPoint(x: 0 - self.size.width / 4, y: 0 - (scrollCell.size.height - self.size.height / 2))
    scrollCell.anchorPoint = CGPoint.zero
    scrollCell.zPosition = 0
    self.addChild(scrollCell)

//        let backgroundImage = SKSpriteNode(imageNamed: "bg")
//        backgroundImage.position = CGPoint(x: self.frame.midX, y: self.frame.midY)
//        self.addChild(backgroundImage)

    let column1PosX = scrollCell.size.width / 3 / 2
    let column2PosX = scrollCell.size.width / 2
    let column3PosX = scrollCell.size.width / 3 / 2 + scrollCell.size.width / 3 * 2
    var colCount = 0
    var rowCount = 0

    for button in buttons {

        var posX: CGFloat = column2PosX
        if colCount == 0 {
            posX =  column1PosX
        }
        else if colCount == 2 {
            posX =  column3PosX
            colCount = -1
        }

        let indexOffset = CGFloat(rowCount) * (levelButtonSize.height + padding)
        let posY = scrollCell.size.height - levelButtonSize.height / 2 - (indexOffset + padding / 2)
        button.position = CGPoint(x: posX, y: posY)
        button.setScale(0.5)
        button.zPosition = 10
        scrollCell.addChild(button)

        if colCount == -1 {
            rowCount += 1
        }
        colCount += 1
    }
}

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

    if let touch = touches.first as UITouch! {

        self.scrollCell.removeAllActions()
        initialTouch = touch.location(in: self.scene!.view)
        moveAmtY = 0
        initialPosition = self.scrollCell.position
    }
}

override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {

    if let touch = touches.first as UITouch! {

        let movingPoint: CGPoint = touch.location(in: self.scene!.view)

        moveAmtY = movingPoint.y - initialTouch.y

        scrollCell.position = CGPoint(x: initialPosition.x, y: initialPosition.y - moveAmtY)
    }
}

override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {

    checkForResettingSlider()
    yMoveActions(moveTo: -moveAmtY)
}

func checkForResettingSlider() {

    let topPos: CGFloat = scrollCell.size.height - self.size.height / 2
    let bottomPos = 0 - (self.size.height / 2)

    if scrollCell.position.y > bottomPos {

        let move = SKAction.moveTo(y: bottomPos, duration: 0.3)
        move.timingMode = .easeOut
        scrollCell.run(move)
    }

    if scrollCell.position.y < -topPos {

        let move = SKAction.moveTo(y: -topPos, duration: 0.3)
        move.timingMode = .easeOut
        scrollCell.run(move)
    }
}

func yMoveActions(moveTo: CGFloat) {

    let move = SKAction.moveBy(x: 0, y: (moveTo * 1.5), duration: 0.3)
    move.timingMode = .easeOut

    self.scrollCell.run(move, completion: { self.checkForResettingSlider() })
}

【讨论】:

  • 我实现了您的解决方案,但是当我滚动到顶部时,它会移动到可见级别按钮之外,当我滚动到底部时,它只显示最低行按钮。如上图所示,我在级别菜单中添加了两行,因此我设置了scrollCell = SKSpriteNode(color: .blue, size: CGSize(width: self.size.width, height: 1.5*self.size.height))。此外,当我触摸其中一个按钮(试图滚动)时,它会开始触摸级别。如何让滚动屏幕与点击按钮区分开来?
  • 我认为checkForResettingSlider() 可能有问题,导致行为不太确定是什么
  • 我猜你一直很忙。我没能解决这个问题,我仍然有同样的问题
  • 谢谢,虽然它有一些我无法解决的问题。它正在截断第一行。我不知道你为什么要缩小比例,但我删除了那条线,并且我还设置了 ScrollCell 位置 (0, 0),因为第一列不在屏幕上。这是我当前滚动菜单的链接imgur.com/9w6AxwT
  • 它被缩放了,因为我没有你的图片而且我使用的图片太大了
猜你喜欢
  • 1970-01-01
  • 2014-06-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-01-07
  • 1970-01-01
相关资源
最近更新 更多