创建多个略有变化的精灵节点?

Posted

技术标签:

【中文标题】创建多个略有变化的精灵节点?【英文标题】: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 语言还很陌生,我还不是很先进,但我希望能得到帮助。

【问题讨论】:

【参考方案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 约定是只有类型大写...

【讨论】:

以上是关于创建多个略有变化的精灵节点?的主要内容,如果未能解决你的问题,请参考以下文章

快速创建具有相同纹理的多个精灵(节点)

iOS7 SpriteKit 如何对两个或多个精灵节点子节点的动画进行分组?

用点击在彼此之上创建多个节点

如何控制多个同名精灵套件节点?

多个精灵节点,只出现一个

nodeAtPoint 错误的节点