I use a function (shown below) to spawn a coin node in specific locations at random using an array.
Using this function, I am trying to incorporate more than one coin node (that are slightly different from one another) into this function so that multiple nodes can use this array to spawn and function just like the first coin node.
The problem that I have is that when I incorporate another node into this function or make a new but similar function for the 2nd node I get a Thread 1 SIGABERT error after the game crashes.
I currently have two separate functions for each node that are very similar, but with slight differences to accommodate each node.
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")
}
OK, there are quite a lot of issues here, the main ones being the extreme duplication of code and having your generateCoin...
-functions doing way too much. So here goes:
You state in the comments that the scene should have two coins spawning at different times at one of four possible positions. If the scene has two coins, then the scene has two coins. Let's just create these as properties and be done with it:
// 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
}
Now, these coins are not yet added to the scene nor do they have a proper position, this sounds like a fitting scope for another function:
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)
}
}
Finally you want to have this function being called so do the following in your scene's init or setup:
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))