SpriteKit:枚举时如何添加/删除节点并避免出现变异异常?

时间:2016-03-02 09:34:19

标签: ios sprite-kit swift2 sknode

我将SKScene渲染为仅仅是一个节点网格,我在其中投影由更大的期刊网格构建的数据结构。

当要求在网格中的(i,j)位置渲染节点时,代码会查找媒体(纹理)可用性,在这种情况下,添加SKSpriteNode。但如果不能立即使用,请从远程服务器请求纹理(当然在线程中)。因此,由于它不是立即可用的,因此代码会创建一个后备SKShapeNode,以便在下载纹理时让用户可以看到它。

当接收纹理时,将SKShapeNode替换为SKSpriteNode,并使用由接收纹理构成的新创建的SKSpriteNode。

每个节点都以其在网格中的位置命名。 "((I),(J))"

除此之外,我处理一个捏合手势,负责重新排列节点的位置,这取决于捏的教育程度(坚果不对场景应用刻度)。

一切正常,但不幸的是,我没有找到办法避免在枚举时改变精灵节点子列表。

我该怎么办?

    for i in 0..<tilesh {
        for j in 0..<tilesw {
            let row = i
            let col = j + band * tilesw

            if let journal = Journal.journalForLevel(level, row: row, col: col) {

                // --- ask for the journal cover, but if not straght availble, fetch from cache or remote server
                let _ = journal.getCover {

                    // If completion block is invoked, that mean the cover has been fetch from a cache level
                    (journal: Journal) in

                    // If cover is now available, we simply creat the tile as a SKNode
                    createteOrUpdateJournalNode(panel, journal: journal, row: i, col: j)
                }

                // --- Draw journal at each tile if cover already avail, just draw it
                createteOrUpdateJournalNode(panel, journal: journal, row: i, col: j)
            }
            // --- No journal available
            else {
                createteOrUpdateJournalNode(panel, journal: nil, row: i, col: j)
                print("No journal avail for band=\(band) at row=\(row), col=\(col)")
            }
        }   // each j
    }   // each i






   func createteOrUpdateJournalNode(parent: Panel, journal: Journal?, row: Int, col: Int) {

        var node : SKNode

        let alpha:CGFloat = 1 //0.5 + 0.5 * CGFloat((band+1)/panels.count)

        if let journal = journal {

            if let _ = journal.cover {

                let cover   = prepareCover(journal)
                let texture = SKTexture(image: cover)
                let n       = SKSpriteNode(texture: texture)
                node = n

                n.anchorPoint   = CGPoint(x: 0, y: 0)
            }
            else {
                let n       = SKShapeNode(rect: CGRect(x: 0, y: 0, width: w, height: h))
                node = n

                let c = 0.5 + CGFloat(arc4random() % 127) / 127
                n.fillColor     = UIColor(red: c, green: c, blue: 1, alpha: alpha)
                n.strokeColor   = UIColor.blueColor()
                n.lineWidth     = 4
            }
        }
        else {
            let n       = SKShapeNode(rect: CGRect(x: 0, y: 0, width: w, height: h))
            node = n

            let c = 0.5 + CGFloat(arc4random() % 127) / 127
            n.fillColor     = UIColor(red: 1, green: c, blue: c, alpha: alpha)
            n.strokeColor   = UIColor.redColor()
            n.lineWidth     = 4
        }

        let name = "\(band)-\(row)-\(col)"
        node.name = name
        node.position       = CGPoint(x: CGFloat(col) * w * timeScale, y: CGFloat(row) * h)

        if let n = parent.childNodeWithName(name) {
            //n.runAction(SKAction.removeFromParent())
            print ("---- should prune node from band \(band) at \(name)")
        }

        print(">>>> Creating node \(name)")
        parent.addChild(node)
        print("<<<<")
    }

2 个答案:

答案 0 :(得分:1)

也许你可以通过使用SKSpriteNode作为临时占位符来完全避免突变问题,并且只在收到数据时指定新纹理。这样,使用相同的对象/实例,并且您的枚举不会受到影响

答案 1 :(得分:0)

我解决了这个问题,发现可以安全地改变SpriteKit update()函数中的节点列表,如下所示:

   // SpriteKits gameloop function
    override func update(currentTime: CFTimeInterval) {

        // Mutate list
        for p in panels {
            p.addNodes()
        }
    }

p指的是一个Panel数组(参见答案后面的Panel类)。

我在稍微修改后的createOrUpdateJounralNode()版本中从渲染循环中准备了其他节点,如下所示:

    let node = createOrUpdateJournalNode(nil, row: i, col: j)
    panel.addNode(node)

其中panel.addNode()只是引用代码段,如下所示:

class Panel {
    var addNodesList = [SKNode]()

    func addNode(node: SKNode) {
        addNodesList.append(node)
    }

    func addNodes() {

        if addNodesList.count > 0 {
            for n in addNodesList {
                if let name = n.name {
                    if let n = childNodeWithName(name) {
                        n.removeFromParent()
                        print("---- removing node \(name)")
                    }
                }
                addChild(n)
                print("++++ adding node \(name)")
            }

            addNodesList = [SKNode]()
        }
    }
}

createOrUpdateJournalNode()的略微修改版本如下:

    func createOrUpdateJournalNode(journal: Journal?, row: Int, col: Int) -> SKNode {
       // same code than before except we don't add child to parent, but simply return the node

       return node
    }