【问题标题】:Spawning multiple coin node(s) using an array Swift SpriteKit使用数组 Swift SpriteKit 生成多个硬币节点
【发布时间】:2016-06-16 06:22:30
【问题描述】:

我使用一个函数(如下所示)使用数组在特定位置随机生成一个硬币节点。

使用此函数,我试图将多个硬币节点(彼此略有不同)合并到此函数中,以便多个节点可以使用此数组来生成和运行,就像第一个硬币节点一样。

我遇到的问题是,当我将另一个节点合并到此函数中或为第二个节点创建一个新但类似的函数时,我在游戏崩溃后收到一个线程 1 SIGABERT 错误。

我目前为每个节点有两个独立的函数,它们非常相似,但在适应每个节点时略有不同。

 func generateCoinZero() {

    if(self.actionForKey("spawningCoinZero") != nil){return}
    let coinTimerZero = SKAction.waitForDuration(2, withRange: 7)

    let spawnCoinZero = SKAction.runBlock {
    let coinZeroTexture = SKTexture(imageNamed: "coinZero")

    self.coinZero = SKSpriteNode(texture: coinZeroTexture)
    self.coinZero.physicsBody = SKPhysicsBody(circleOfRadius: self.coinZero.size.height / 12)
    self.coinZero.physicsBody?.dynamic = false
    self.coinZero.physicsBody?.allowsRotation = false
    self.coinZero.zPosition = 1

    self.coinZero.physicsBody?.categoryBitMask = ColliderType.coinZeroCategory
    self.coinZero.physicsBody?.contactTestBitMask = ColliderType.playerCategory
    self.coinZero.physicsBody?.collisionBitMask = 0

    self.player.physicsBody?.categoryBitMask = ColliderType.playerCategory
    self.player.physicsBody?.contactTestBitMask = 0
    self.player.physicsBody?.collisionBitMask = ColliderType.boundary

    var coinPositionZero = Array<CGPoint>()
    coinPositionZero.append((CGPoint(x:250, y:139)))
    coinPositionZero.append((CGPoint(x:790, y:298)))
    coinPositionZero.append((CGPoint(x:225, y:208)))
    coinPositionZero.append((CGPoint(x:220, y:237)))

    let spawnLocationZero = coinPositionZero[Int(arc4random_uniform(UInt32(coinPositionZero.count)))]
    let actionZero = SKAction.repeatActionForever(SKAction.moveToX(+self.xScale, duration: 2.0))

    self.coinZero.runAction(actionZero)
    self.coinZero.position = spawnLocationZero
    self.addChild(self.coinZero)
    print(spawnLocationZero)
    }

  let sequenceZero = SKAction.sequence([coinTimerZero, spawnCoinZero])
    self.runAction(SKAction.repeatActionForever(sequenceZero), withKey: "spawningCoinZero") 
}

func generateCoinTwo() {

    if(self.actionForKey("spawnCoinTwo") != nil){return}
    let coinTimerTwo = SKAction.waitForDuration(2, withRange: 7)

    let spawnCoinTwo = SKAction.runBlock {

        let coinTwoTexture = SKTexture(imageNamed: "coinTwo")
        self.coinTwo = SKSpriteNode(texture: coinTwoTexture)
        self.coinTwo.physicsBody = SKPhysicsBody(circleOfRadius: self.coinTwo.size.height / 12)
        self.coinTwo.physicsBody?.dynamic = false
        self.coinTwo.physicsBody?.allowsRotation = false
        self.coinTwo.zPosition = 1
        self.addChild(self.coinTwo)

        var coinPositionTwo = Array<CGPoint>()
        coinPositionTwo.append((CGPoint(x:250, y:139)))
        coinPositionTwo.append((CGPoint(x:790, y:298)))
        coinPositionTwo.append((CGPoint(x:225, y:208)))
        coinPositionTwo.append((CGPoint(x:220, y:237)))

        let spawnLocationTwo = coinPositionTwo[Int(arc4random_uniform(UInt32(coinPositionTwo.count)))]
         let actionTwo = SKAction.repeatActionForever(SKAction.moveToX(+self.xScale, duration: 2.0))

        self.coinTwo.runAction(actionTwo)
        self.coinTwo.position = spawnLocationTwo
        self.addChild(self.coinTwo)
        print(spawnLocationTwo)
    }

    let sequenceTwo = SKAction.sequence([coinTimerTwo, spawnCoinTwo])
    self.runAction(SKAction.repeatActionForever(sequenceTwo), withKey: "spawnCoinTwo")
}

【问题讨论】:

  • 我经常看到这个...为什么你一直引用最后一个生成的硬币?同样在闭包内使用 self 与 SKAction.repeatForever 结合会产生强大的引用循环......哪条线崩溃?
  • 在您的 spawnCoinTwo SKAction 块中,您创建了 2 个不可变变量 - coinTwoTexture 和 spawnLocationTwo。当此操作第二次运行时,这些将失败,因为变量已经存在。尝试将这些更改为 'var' 并将它们移到 spawnCoinTwo SKAction 块之外。
  • 你能发布确切的失败信息吗?
  • 坦率地说,这有点乱。你到底想发生什么?一次生成n个硬币?还是同时n个硬币?
  • @Whirlwind,Xcode 似乎没有告诉我是哪一行导致了问题,因为游戏播放了几秒钟然后崩溃并给了我原始问题中显示的错误消息。跨度>

标签: arrays swift sprite-kit collision-detection skphysicsbody


【解决方案1】:

好的,这里有很多问题,主要是代码的极端重复以及您的generateCoin...-函数做得太多。所以这里是:

您在 cmets 中声明场景应该有 两个 硬币在不同时间在四个可能位置之一生成。如果场景有 两个 硬币,那么场景有 两个 硬币。让我们将它们创建为属性并完成它:

// Your two coin properties 
let coin1 = coinNode()
let coin2 = coinNode()

// the function from which they are created
func coinNode() -> SKSpriteNode {
    let coinNode = SKSpriteNode(imageNamed: "coinZero")
    coinNode.physicsBody = SKPhysicsBody(circleOfRadius: coinNode.size.height / 2)
    coinNode.physicsBody?.dynamic = false
    coinNode.physicsBody?.allowsRotation = false
    coinNode.zPosition = 1

    coinNode.physicsBody?.categoryBitMask = ColliderType.coinZeroCategory
    coinNode.physicsBody?.contactTestBitMask = ColliderType.playerCategory
    coinNode.physicsBody?.collisionBitMask = 0 // A ColliderType.none would be lovely...

    return coinNode
}

现在,这些硬币还没有添加到场景中,也没有合适的位置,这听起来像是另一个功能的合适范围:

func addCoin() {
    let positions = [ CGPoint(x:250, y:139), CGPoint(x:790, y:298), CGPoint(x:225, y:208), CGPoint(x:220, y:237)]
    let position = positions[Int(arc4random_uniform(UInt32(positions.count)))]

    if coin1.parent == nil {
        coin1.position = position
        addChild(coin1)
    } else if coin2.parent == nil {
        coin2.position = position
        addChild(coin2)
    }
}

最后,您希望调用此函数,因此请在场景的初始化或设置中执行以下操作:

let delay = SKAction.waitForDuration(1) // or however long you want it to be between each spawn
let addCoinCall = SKAction.runBlock({ self.addCoin() })
let spawnSequence = SKAction.sequence([delay, addCoinCall])
runAction(SKAction.repeatActionForever(spawnSequence)) 

【讨论】:

  • 问题已解决,非常感谢您的帮助。谢谢!
  • 这样使用 self 时要小心。因为动作是重复的,所以它会排队等待下一帧,并且因为块强烈地捕捉自我,这可能会产生强参考循环,例如在转换到另一个场景时。您可以通过两种方式解决此问题。在捕获列表中使用弱/无主 self,或在转换之前删除此操作。
  • @Whirlwind 好点,我个人养成了在我要摆脱的任何节点上调用 removeAllActions 的习惯。
【解决方案2】:

你不能addChild twice,把addChild放在runBlock之外,确保你是addChild一次。

如果你想放多个硬币,最好复制你的节点并添加到场景中。 您可以在函数外创建一个像 coinZero 这样的节点,然后在函数内部执行以下操作:

let coinToAdd = coinZero.copy()

【讨论】:

  • 硬币有物理体,我不认为copy复制了这个,我不认为它复制了任何可能添加到硬币中的孩子
  • 对了,那个拷贝也是物理礼仪,我做这个
  • 很酷,他们一定已经解决了这个问题,因为它并不总是
  • :) 请尝试一下,可能我有一个很好的错误! :) 我在 .sks 文件中复制了一个自定义的 SKNode 类。只能以这种方式工作吗?
  • 您好 Simone,我还在学习 swift,关于您的答案,我有一个问题要问您。我只是想验证你所说的话,以便我可以确定我理解它。我将消除 ' generateCoinTwo ' 函数并在 ' generateCoinZero ' 函数中使用 ' let coinTwo = coinZero.copy() '?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-08-31
  • 1970-01-01
相关资源
最近更新 更多