【问题标题】:creating multiple sprite nodes with slight variations?创建多个略有变化的精灵节点?
【发布时间】:2016-07-25 09:37:52
【问题描述】:

我有一个显示多个成就的游戏菜单,这些成就被定义为 SKSpriteNodes,其中有 18 个,它们的位置只有轻微的变化,这里是代码的 sn-p:

    Achievement1 = SKSpriteNode(color: SKColor.whiteColor(), size: CGSize(width: 100, height: 100))
    Achievement1.position = CGPointMake(-120, 100)
    page1ScrollView.addChild(Achievement1)

    Achievement2 = SKSpriteNode(color: SKColor.whiteColor(), size: CGSize(width: 100, height: 100))
    Achievement2.position = CGPointMake(0, 100)
    page1ScrollView.addChild(Achievement2)

    Achievement3 = SKSpriteNode(color: SKColor.whiteColor(), size: CGSize(width: 100, height: 100))
    Achievement3.position = CGPointMake(120, 100)
    page1ScrollView.addChild(Achievement3)

    Achievement4 = SKSpriteNode(color: SKColor.whiteColor(), size: CGSize(width: 100, height: 100))
    Achievement4.position = CGPointMake(-120, -25)
    page1ScrollView.addChild(Achievement4)

我还竭尽全力将它们一一定义为 vars,如下所示:

  var Achievement1: SKSpriteNode!
  var Achievement2 = SKSpriteNode()
  var Achievement3 = SKSpriteNode()
  var Achievement4 = SKSpriteNode()
  var Achievement5 = SKSpriteNode()
  var Achievement6 = SKSpriteNode()
  var Achievement7 = SKSpriteNode()
  var Achievement8 = SKSpriteNode()

它看起来一团糟,只是占用了太多空间。我希望能够定义所有精灵节点,并让它们都能够被按下以显示一个框,说明成就的用途,如下所示:

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

    let touch: UITouch = touches.first!
    let location: CGPoint = touch.locationInNode(self)
    let node: SKNode = self.nodeAtPoint(location)


    if (node == Achievement1) {

        //achievement details here

   }

我对这种 swift 语言还很陌生,我还不是很先进,但我希望能得到帮助。

【问题讨论】:

    标签: swift sprite-kit swift2 skspritenode


    【解决方案1】:

    如果您认为您的代码一团糟,请尝试在您的代码中找到模式

    看到那些Achievement1Achievement2Achievement3Achievement4 的东西了吗?当您看到这种模式时,您可能应该创建一个数组来存储成就。

    我确定你知道如何使用数组,所以我不会过多地谈论它。有关详细信息,您可以转到 Array 类的定义。

    您可能注意到的另一种模式是使用相同的参数来创建精灵节点。成就之间的唯一区别是他们的位置。

    解决此问题的最佳方法是创建一个方法:

    func createAchievement(location: CGPoint) -> SKSpriteNode {
        let node = SKSpriteNode(color: SKColor.whiteColor(), size: CGSize(width: 100, height: 100))
        node.position = location
        return node
    }
    

    您只需要一行就可以将新成就添加到上述数组中:

    someArray.append(createAchievement(CGPointMake(-120, 100)))
    

    编辑:

    如果你使用indexOf(_:)(或swift 3中的index(of:)),你可以创建一个switch语句而不是if语句:

    switch someArray.indexOf(node) {
        case 0:
            // this means that the first achievement is tapped!
        case 1:
            // this means that the second achievement is tapped!
        case 2:
            // this means that the third achievement is tapped!
    }
    

    【讨论】:

    • 这是否仍然允许我使用在我的 touchesbegan 方法中生成的节点?
    • @Astrum 当然是的!要检查node 是否是第一个成就,请使用node == someArray[0]!要检查第二个成就,请使用node == someArray[1]。剩下的你自己搞定!
    • @Astrum 您也可以使用 Grimxn 在他的回答中提到的 index(of:) 方法。但如果您使用的是 Swift 2.x,请改用 indexOf(_:)
    • 为什么我必须在我的 touchesbegan 方法中使用那个 indexof(_:) ?这是否让我不必在 touches begin 方法中单独写出它们?
    • 如果你使用indexOf,你可以创建一个switch语句来切换被触摸节点的索引(更优雅的IMO)而不是if语句(不太优雅)@Astrum
    【解决方案2】:

    关于布局当你有大量的项目要显示时,你可以考虑使用表格或页面控件。因为我很懒,我不喜欢只滚动表格来查看所有游戏成就,所以通常我更喜欢使用 PageControl。 您可以在UIKitUIPageControl 中构建并将其集成到您的游戏菜单中。 如果你不知道如何集成UIPageControl,你可以使用这个sprite-kit项目GBPageControl

    import GBPageControl
    
    var pageControl:PageControl!
    //Add the page control to the scene. Add any content that will be paged directly to the pageControl:
    override func didMoveToView(view: SKView) {
        pageControl = PageControl(scene: self)
        addContent()
        pageControl.enable(4)
    }
    
    private func addContent() {
        for var i = 0; i < 4; i++ {
            let node = SKShapeNode(circleOfRadius: 10)
            node.strokeColor = UIColor.blueColor()
            let x = self.size.width / 2.0 + self.size.width * CGFloat(i)
            let y = self.size.height / 2.0
            node.position = CGPoint(x:x, y:y)
            pageControl.addChild(node)
        }
    }
    
    override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
        for touch in touches {
            if pageControl.handleTouch(touch) {
                //no op
            }
            else {
                //handle touch
            }
        }
    }
    override func willMoveFromView(view: SKView) {
        pageControl.willMoveFromView(view)
    }
    

    输出

    更新

    关于你可以尝试做的成就代码:

    enum MedalType: Int {
        case Gold = 1
        case Silver = 2
        case Bronze = 3
    }
    class Achievement:SKSpriteNode {
        init(color:SKColor,size:CGSize,name:String,medalType:MedalType) {
            super.init(texture: nil,color:color,size:size)
            self.name = name
        }
        required init?(coder aDecoder: NSCoder) {
            fatalError("init(coder:) has not been implemented")
        }
    }
    
    class GameScene: SKScene {
        var achievements:[Achievement]!
        var aNames: [String]!
        var totalAchievements: Int = 45
    
      override func didMoveToView(view: SKView) {
        var counter : Int = 0
        let deltaX:CGFloat = 120
        let deltaY:CGFloat = 10
        for i in 0..<totalAchievements {
            var aColor = SKColor.whiteColor()
            var aSize = CGSizeMake(100,100)
            var medal = MedalType.Bronze
    
            switch i {
            case 10:
                aColor = SKColor.redColor()
                aSize = CGSizeMake(100,150)
                medal = MedalType.Silver
            case 25:
                aColor = SKColor.blueColor()
                aSize = CGSizeMake(100,200)
                medal = MedalType.Gold
            default:
                break
            }
            let name = "achievement\(i)"
            let a = Achievement.init(color: aColor, size: aSize, name: name, medalType: medal)
            aNames.append(name)
    
            //handle your position has you wish with counter, deltaX e deltaY
            //...
            a.position = CGPointMake(deltaX, deltaY)
            addChild(a)
           }
        }
        override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
    
            let touch: UITouch = touches.first!
            let location: CGPoint = touch.locationInNode(self)
            let node: SKNode = self.nodeAtPoint(location)
    
            if (aNames.contains(node.name!)) {
    
                print("You have touch achievement \(node.name)")
                let currentAchievement = achievements[aNames.indexOf(node.name!)!]
                // Use your currentAchievement touched
            }
        }
    }
    

    【讨论】:

      【解决方案3】:

      你可以使用数组...

      let achievements = [SKSpriteNode](repeating: SKSpriteNode(color: SKColor.white(), size: CGSize(width: 100, height: 100)), count: 8) // Swift 3 colour name
      let positions = [CGPoint(x: -120, y: 100), CGPoint(x: 0, y: 100) /* ... */]
      for i in 0 ..< min(achievements.count, positions.count) { // For safety - obviously these should be the same
          achievements[i].position = positions[i]
      }
      
      // Then in your touch routine...
      if let index = achievements.index(of: self.nodeAtPoint(location)) {
          // do something with achievements[index]
      }
      

      ...并且不要大写变量 - Swift 约定是只有类型大写...

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-01-07
        • 2022-10-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多