How to animate a matrix changing the sprites one by one? - swift

I´m making a little game were I have a matrix compose for SKSpriteNode and numbers, when the game its over I´m trying to make an animation were I go over the matrix changing only the sprite one by one following the order of the numbers. Look the
Board (The squares are in a Sknode and the number in other Sknode)
The Idea is change the sprite to other color and wait 2 sec after change the next but I can´t do it. I don't know how to change the sprite one by one. I make this function "RecoverMatrix()", this change the sprites but all at once, it is as if not take the wait, he change all the sprites and before wait the 2 sec.
func RecoverMatrix() {
var cont = 1
TileLayer.removeAllChildren()
numLayer.removeAllChildren()
let imageEnd = SKAction.setTexture(SKTexture(imageNamed: "rectangle-play"))
let waiting = SKAction.waitForDuration(2)
var scene: [SKAction] = []
var tiles: [SKSpriteNode] = []
while cont <= 16 {
for var column = 0; column < 4; column++ {
for var row = 0; row < 4; row++ {
if matrix[column][row].number == cont {
let label = SKLabelNode()
label.text = "\(matrix[column][row])"
label.fontSize = TileHeight - 10
label.position = pointForBoard(column, row: row)
label.fontColor = UIColor.whiteColor()
let tile = SKSpriteNode()
tile.size = CGSize(width: TileWidth - 3, height: TileHeight - 3)
tile.position = pointForBoard(column, row: row, _a: 0)
TileLayer.addChild(tile)
numLayer.addChild(label)
tiles.append(tile)
scene.append(SKAction.sequence([imageEnd, waiting]))
tile.runAction(imageEnd)
runAction(waiting)
didEvaluateActions()
}
}
}
cont++
}
for tile in tiles {
tile.runAction(SKAction.sequence(scene))
self.runAction(SKAction.waitForDuration(1))
}
}
So, I need help, I don't find the way to make this animation. I really appreciate the help. Thanks!

This is how you can run an action on every node at the same time (using a loop to loop through all the tiles):
class GameScene: BaseScene, SKPhysicsContactDelegate {
var blocks: [[SKSpriteNode]] = []
override func didMoveToView(view: SKView) {
makeBoard(4, height: 4)
colorize()
}
func makeBoard(width:Int, height:Int) {
let distance:CGFloat = 50.0
var blockID = 1
//make a width x height matrix of SKSpriteNodes
for j in 0..<height {
var row = [SKSpriteNode]()
for i in 0..<width {
let node = SKSpriteNode(color: .purpleColor(), size: CGSize(width: 30, height: 30))
node.name = "\(blockID++)"
if let nodeName = node.name {node.addChild(getLabel(withText: nodeName))}
else {
//handle error
}
node.position = CGPoint(x: frame.midX + CGFloat(i) * distance,
y: frame.midY - CGFloat(j) * distance )
row.append(node)
addChild(node)
}
blocks.append(row)
}
}
func colorize() {
let colorize = SKAction.colorizeWithColor(.blackColor(), colorBlendFactor: 0, duration: 0.5)
var counter = 0.0
let duration = colorize.duration
for row in blocks {
for sprite in row {
counter++
let duration = counter * duration
let wait = SKAction.waitForDuration(duration)
sprite.runAction(SKAction.sequence([wait, colorize]))
}
}
}
func getLabel(withText text:String) -> SKLabelNode {
let label = SKLabelNode(fontNamed: "ArialMT")
label.fontColor = .whiteColor()
label.text = text
label.fontSize = 20
label.horizontalAlignmentMode = .Center
label.verticalAlignmentMode = .Center
return label
}
}
And the result:
So basically, as I said in the comments, you can run all the actions at the same moment, it is just about when the each action will start.

You seem to imagine that runAction(waiting) means that you code pauses and waits, pausing between loops. It doesn't (and in fact there is no way to do that). Your code loops through all the loops, now, KABOOM, immediately.
Thus, all the actions are configured immediately and are performed together.

Related

SKAction & SKSpriteNode trouble

I'm in the process of creating a card game in Swift using SKSprite Nodes to show the card faces.
In my 'deal' function, it deals 3 cards to each player, one at a time in a 'round-robin' fashion. This is working fine but I'm trying to add a bit of animation - I'm trying to make it show each card being dealt to the local player by animating it moving from the deck to the players hand position.
I can get the Sprite Nodes to show without the animation but when I try with SKAction, it gives me the following error after the action is completed:
reason: 'Attemped to add a SKNode which already has a parent: name:'local player node' texture:[ 'CARD39' (203 x 350)] position:{281.25, 100.05000305175781}
class GameScene: SKScene {
let tempCard = SKSpriteNode(texture: SKTexture(imageNamed: "back"))
func deal() {
players = createPlayers(with: numberOfPlayers)
tempCard.setScale((screenSize.width/100) * 0.2)
tempCard.zPosition = 10
tempCard.name = "tempcard"
addChild(tempCard)
let localPlayer = 0
var i = 0
repeat {
print("Card number: \(i)")
var x = 0
let xPos = screenSize.width * (0.25 * CGFloat(i+1))
players.forEach { player in
let newCard = self.deck.dealOneCard()
player.hand.addCard(card: newCard)
localPlayerNode = players[localPlayer].hand[i].cardImage()
localPlayerNode.position = CGPoint(x: xPos, y: screenSize.height * 0.15)
localPlayerNode.setScale((screenSize.width/100) * 0.2)
localPlayerNode.name = "local player node"
if player.id == localPlayer {
let moveCard = SKAction.move(to: CGPoint(x: xPos, y: screenSize.height * 0.15),duration: 1.5)
//addChild(localPlayerNode) --using this instead of SKAction works
tempCard.run(moveCard, completion: {() -> Void in
self.tempCard.removeFromParent()
self.addChild(self.localPlayerNode)
})
}
x+=1
}
i+=1
} while i<3
I believe the problem is with adding the player nodes within your loop, and then not removing them afterwards. I'm sure you don't want to remove the players every time you call the " deal() " function so you should add the player nodes in the didMove() method.
I've put together a playground that demonstrates this (github Link).
I've tried to use a delay to make the cards deal 1 by one, but this is a different problem you will need to look elsewhere to solve. (Something with the .run( action) makes it so that it doesn't actually animate until the loop is complete.
example gif with bad pixel art
class GameScene: SKScene {
let scale : CGFloat = 50
var deck : [String] = []
let composition = deckComp()
let numberOfPlayers = 3
var players : [Player] = []
override func didMove(to view: SKView) {
// creates deck
for c in deckComp().colors {
for s in deckComp().suits {
deck.append( s + " of " + c )
}
}
players = createPlayers(numberOfPlayers: numberOfPlayers, center : CGPoint(x : 25, y : 25))
// setup the scales, and players
for plyr in players {
plyr.setScale(scale: (frame.width/10000) * scale)
addChild( plyr.node)
}
}
func createPlayers(numberOfPlayers : Int, center : CGPoint) -> [Player] {
let radius = Float(5*scale)
let two_pi = 2 * 3.14159
let angular_positions = two_pi / Double(numberOfPlayers)
var players_out : [Player] = []
for i in 0...numberOfPlayers - 1 {
let sprite = SKSpriteNode(texture: SKTexture(imageNamed: "card_player.png"))
sprite.zPosition = 1
sprite.position = CGPoint( x : center.x + CGFloat(radius * sin( Float(angular_positions) * Float(i) )), y : center.y + CGFloat(radius * cos( Float(angular_positions) * Float(i) )) )
sprite.texture?.filteringMode = .nearest // .linear for blurry, .nearest for pixely
let player_instance = Player(node : sprite, name : "Player " + String(i + 1), id : Int8(i + 1) )
players_out.append(player_instance)
}
return players_out
}
func deal() {
// I moved the setscale stuff for player sprites to didMove()
// first check if there is enough in deck
if deck.count > players.count {
var i = 0
repeat {
// add the temp card
let tempCard = SKSpriteNode(texture: SKTexture(imageNamed: "back"))
tempCard.size = CGSize( width: tempCard.size.width * (frame.width/10000) * scale, height : tempCard.size.height * (frame.width/10000) * scale )
tempCard.zPosition = 10
tempCard.texture?.filteringMode = .nearest
self.addChild(tempCard)
// done adding temporary card
let xPos = frame.width * (0.25 * CGFloat(i+1))
tempCard.position = CGPoint(x : xPos, y : 0.75 * frame.height)
let newCard = self.deck.popLast() // replaced dealOneCard() since I haven't defined it
players[i].addCard(card: newCard!) // removed hand.addCard(), since I don't have the array extensions
// player.name = "local player node"
let moveCard = SKAction.move(to: players[i].node.position ,duration: 1.5)
//addChild(localPlayerNode) --using this instead of SKAction works
tempCard.run(moveCard, completion: { () -> Void in tempCard.removeFromParent(); })
i += 1
} while i < players.count
} else { print("not enough cards to deal to everyone")} // when deck is empty
}
override func mouseUp(with event: NSEvent) {
deal()
}

enumareteChildNodes with collision detection swift

I am trying to code a word collision detection game.
The problem is that before I add rectangle as a background of my words, all of my codes are working, I can detect the collision and take action. but after add rectangle, I have to change my parents of the word and I add it as the child of background.
This the function that I create word:
func giveWords() {
randomIndex = Int.random(in: 0 ..< lastWords.count)
word = SKLabelNode(text: "\(lastWords[randomIndex])")
lastWords.remove(at: randomIndex)
word.fontSize = 17
word.name = "word"
word.fontName = "HelveticaNeue-Bold"
backgroundWord = SKShapeNode(rect: CGRect(x: 0, y: 0, width: (word.frame.width + 3), height: (word.frame.height + 2)), cornerRadius: 4)
word.physicsBody? = SKPhysicsBody(rectangleOf: self.size)
word.physicsBody?.collisionBitMask = 0
word.physicsBody?.contactTestBitMask = 0
word.physicsBody?.categoryBitMask = 1
word.physicsBody?.affectedByGravity = false
word.physicsBody?.isDynamic = false
word.position = CGPoint(x:(backgroundWord.position.x + word.frame.width/2 + 1 ), y: (backgroundWord.position.y) + 4)
let number = Int.random(in: 1 ..< 9)
backgroundWord.position = CGPoint(x: (50 * number), y: 450)
word.zPosition = 3
backgroundWord.zPosition = 3
backgroundWord.addChild(word)
addChild(backgroundWord)
}
and this is the code that I check collision:
func checkCollision() {
enumerateChildNodes(withName: "word") { (node, _) in
let word = node as! SKLabelNode
if self.basketNode.frame.intersects(word.frame) {
if self.similarWord.contains(word.text!) {
self.score += 1
self.scoreLabel.text = "\(self.score)"
self.takeWord.append(word.text!)
self.run(self.trueSound)
self.backgroundWord.removeFromParent()
} else {
self.run(self.falseSound)
self.health -= 1
self.healthLabel.text = "HP: \(self.health)"
self.backgroundWord.removeFromParent()
}
}
}
}
I tried physics collision but I did not handle, so I chose this algorithm.
After function called, self.basketNode.frame.intersects(word.frame) returns false, this means collision is not detected.
I couldn't handle why collision is not detected.
Thanks in advance!
I solved it, here is the answer and reason.
The reason behind it is, and the reason why I did not detect self.basketNode.frame.intersects(word.frame) is simple.
I tried to detect word's frame intersection but I should detect its parent which is the background. So I changed the word to the background and after that create a let that help me to access word. Here is the answer btw...
func checkCollision() {
enumerateChildNodes(withName: "word") { (node, _) in
let background = node as! SKShapeNode
if self.basketNode.frame.intersects(background.frame) {
if let word = background.childNode(withName: "string word") as? SKLabelNode {
if self.similarWord.contains(word.text!) {
self.score += 1
self.scoreLabel.text = "\(self.score)"
self.takeWord.append(word.text!)
self.run(self.trueSound)
word.removeFromParent()
background.removeFromParent()
} else {
self.run(self.falseSound)
self.health -= 1
self.healthLabel.text = "HP: \(self.health)"
word.removeFromParent()
background.removeFromParent()
}
}
}
}
btw I got helped from Apple documentation
https://developer.apple.com/documentation/spritekit/sknode/1483024-enumeratechildnodes
Thanks for your effort, I am continuing my project.

Tower defense: turret tracking enemy and shooting issues

Here is my code:
func bombTowerTurnShoot() {
var prevDistance:CGFloat = 1000000
var closesetZombie = zombieArray[0]
self.enumerateChildNodes(withName: "bomb tower") {
node, stop in
if self.zombieArray.count > 0 {
for zombie in self.zombieArray {
if let bombTower = node as? SKSpriteNode {
let angle = atan2(closesetZombie.position.x - bombTower.position.x , closesetZombie.position.y - bombTower.position.y)
let actionTurn = SKAction.rotate(toAngle: -(angle - CGFloat(Double.pi/2)), duration: 0.2)
bombTower.run(actionTurn)
let turretBullet = SKSpriteNode(imageNamed: "Level 1 Turret Bullet")
turretBullet.position = bombTower.position
turretBullet.zPosition = 20
turretBullet.size = CGSize(width: 20, height: 20)
//turretBullet.setScale (frame.size.height / 5000)
turretBullet.physicsBody = SKPhysicsBody(circleOfRadius: max(turretBullet.size.width / 2, turretBullet.size.height / 2))
turretBullet.physicsBody?.affectedByGravity = false
turretBullet.physicsBody!.categoryBitMask = PhysicsCategories.Bullet //new contact
turretBullet.physicsBody!.collisionBitMask = PhysicsCategories.None
turretBullet.physicsBody!.contactTestBitMask = PhysicsCategories.Zombie
self.addChild(turretBullet)
var dx = CGFloat(closesetZombie.position.x - bombTower.position.x)
var dy = CGFloat(closesetZombie.position.y - bombTower.position.y)
let magnitude = sqrt(dx * dx + dy * dy)
dx /= magnitude
dy /= magnitude
let vector = CGVector(dx: 4.0 * dx, dy: 4.0 * dy)
func fire () {
turretBullet.physicsBody?.applyImpulse(vector)
}
func deleteBullet() {
turretBullet.removeFromParent()
}
turretBullet.run(SKAction.sequence([SKAction.wait(forDuration: 0), SKAction.run(fire), SKAction.wait(forDuration: 2.0), SKAction.run(deleteBullet) ]))
let distance = hypot(zombie.position.x - bombTower.position.x, zombie.position.y - bombTower.position.y)
if distance < prevDistance {
prevDistance = distance
closesetZombie = zombie
}
}
}
}
}
}
What this code does is turns a turret towards the closest zombie and shoot at it. As far as I can tell the turret is turn towards the closest zombie (if you can tell whether this code actually accomplishes that or not I would like to know). The bigger problem I am having is that the turrets sometimes shoot more than one bullet. I think it is because it is trying to fire at all zombies in the array not the specified one (the closest to the tower). How can I make it so that the turret only shoots the zombie that is closest?
class GameScene: SKScene, SKPhysicsContactDelegate {//new contact
var zombieArray:[SKSpriteNode] = []
...
...
}
And I append all the zombie to the array once they are added and remove them from the array once they die.
Basically, I don't know what you were doing wrong exactly. You had a ton of stuff going on, and trying to figure out the bug would probably have taken longer than rewriting it (for me at least). So that is what I did.
Here is a link to the project on github:
https://github.com/fluidityt/ShootClosestZombie/tree/master
For me, this was all about separating actions into somewhat distinct methods, and separating actions in general from logic.
You had so much going on, it was hard to test / see which parts were working correctly or not. This is where having somewhat smaller methods come in, as well as separating action from logic.. Your action may work fine, but perhaps it's not getting called due to a logic error.
So, how I implemented this was to just make your bomb turret it's own class.. that way we can have the bomb turret be in charge of most of its actions, and then let gameScene handle most of the implementation / and or logic.
The demo I've uploaded shows two turrets that auto-orient themselves to the closest zombie every frame, then shoot at them every second. Click the screen to add more zombies.
The turrets independently track the closest zombie to them so if you spawn a zombie on the left and the right, then the left turret will shoot at left zombie, and right turret will shoot at right zombie (and only once!).
class BombTower: SKSpriteNode {
static let bombName = "bomb tower"
var closestZombie: SKSpriteNode!
func updateClosestZombie() {
let gameScene = (self.scene! as! GameScene)
let zombieArray = gameScene.zombieArray
var prevDistance:CGFloat = 1000000
var closestZombie = zombieArray[0]
for zombie in zombieArray {
let distance = hypot(zombie.position.x - self.position.x, zombie.position.y - self.position.y)
if distance < prevDistance {
prevDistance = distance
closestZombie = zombie
}
}
self.closestZombie = closestZombie
}
func turnTowardsClosestZombie() {
let angle = atan2(closestZombie.position.x - self.position.x , closestZombie.position.y - self.position.y)
let actionTurn = SKAction.rotate(toAngle: -(angle - CGFloat(Double.pi/2)), duration: 0.2)
self.run(actionTurn)
}
private func makeTurretBullet() -> SKSpriteNode {
let turretBullet = SKSpriteNode(imageNamed: "Level 1 Turret Bullet")
turretBullet.position = self.position
turretBullet.zPosition = 20
turretBullet.size = CGSize(width: 20, height: 20)
//turretBullet.setScale (frame.size.height / 5000)
turretBullet.physicsBody = SKPhysicsBody(circleOfRadius: max(turretBullet.size.width / 2, turretBullet.size.height / 2))
turretBullet.physicsBody?.affectedByGravity = false
// turretBullet.physicsBody!.categoryBitMask = PhysicsCategories.Bullet //new contact
// turretBullet.physicsBody!.collisionBitMask = PhysicsCategories.None
// turretBullet.physicsBody!.contactTestBitMask = PhysicsCategories.Zombie
return turretBullet
}
private func fire(turretBullet: SKSpriteNode) {
var dx = CGFloat(closestZombie.position.x - self.position.x)
var dy = CGFloat(closestZombie.position.y - self.position.y)
let magnitude = sqrt(dx * dx + dy * dy)
dx /= magnitude
dy /= magnitude
let vector = CGVector(dx: 4.0 * dx, dy: 4.0 * dy)
turretBullet.physicsBody?.applyImpulse(vector)
}
func addBulletThenShootAtClosestZOmbie() {
let bullet = makeTurretBullet()
scene!.addChild(bullet)
fire(turretBullet: bullet)
}
}
// TODO: delete bullets, hit detection, and add SKConstraint for tracking instead of update.
// Also, I think that we are iterating too much looking for nodes. Should be able to reduce that.
// Also also, there are sure to be bugs if zombieArray is empty.
class GameScene: SKScene {
var zombieArray: [SKSpriteNode] = []
private func makeBombArray() -> [BombTower]? {
guard self.zombieArray.count > 0 else { return nil }
var towerArray: [BombTower] = []
self.enumerateChildNodes(withName: BombTower.bombName) { node, _ in towerArray.append(node as! BombTower) }
guard towerArray.count > 0 else { return nil }
return towerArray
}
private func towersShootEverySecond(towerArray: [BombTower]) {
let action = SKAction.run {
for bombTower in towerArray {
guard bombTower.closestZombie != nil else { continue } // I haven't tested this guard statement yet.
bombTower.addBulletThenShootAtClosestZOmbie()
}
}
self.run(.repeatForever(.sequence([.wait(forDuration: 1), action])))
}
override func didMove(to view: SKView) {
// Demo setup:
removeAllChildren()
makeTestZombie: do {
spawnZombie(at: CGPoint.zero)
}
makeTower1: do {
let tower = BombTower(color: .yellow, size: CGSize(width: 55, height: 55))
let turretGun = SKSpriteNode(color: .gray, size: CGSize(width: 25, height: 15))
turretGun.position.x = tower.frame.maxX + turretGun.size.height/2
tower.name = BombTower.bombName
tower.addChild(turretGun)
addChild(tower)
}
makeTower2: do {
let tower = BombTower(color: .yellow, size: CGSize(width: 55, height: 55))
let turretGun = SKSpriteNode(color: .gray, size: CGSize(width: 25, height: 15))
turretGun.position.x = tower.frame.maxX + turretGun.size.height/2
tower.addChild(turretGun)
tower.position.x += 200
tower.name = BombTower.bombName
addChild(tower)
}
guard let towerArray = makeBombArray() else { fatalError("couldn't make array!") }
towersShootEverySecond(towerArray: towerArray)
}
private func spawnZombie(at location: CGPoint) {
let zombie = SKSpriteNode(color: .blue, size: CGSize(width: 35, height: 50))
zombieArray.append(zombie)
zombie.position = location
zombie.run(.move(by: CGVector(dx: 3000, dy: -3000), duration: 50))
addChild(zombie)
}
// Just change this to touchesBegan for it to work on iOS:
override func mouseDown(with event: NSEvent) {
let location = event.location(in: self)
spawnZombie(at: location)
}
// I think this could be a constrain or action, but I couldn't get either to work right now.
private func keepTowersTrackingNearestZombie() {
guard let towerArray = makeBombArray() else { return }
for tower in towerArray {
tower.updateClosestZombie()
tower.turnTowardsClosestZombie()
}
}
override func update(_ currentTime: TimeInterval) {
keepTowersTrackingNearestZombie()
}
}

Updating SKLabel text through an SKNode subclass

My Goal: add one to the amount variable of the Achievements Class and then update the text so it shows on the SKLabelNode called "AmountLabel"
So I have a subclass of SKNode that shelters my SKSpriteNode that shows the emblem of the achievement and the SKLabelNodes of the title of the achievement and the amount needed to unlock the achievement As seen below:
class Achievements: SKNode {
var achievementLabel = SKLabelNode()
var achievementTitleLabel = SKLabelNode()
var achievementNode = SKSpriteNode()
var amount = 0
var neededAmount = 0
var Image: String = "locked" {
didSet {
var texture = SKTexture(imageNamed: Image)
}
}
func createAchievement() {
let tex:SKTexture = SKTexture(imageNamed: Image)
achievementNode = SKSpriteNode(texture: tex, color: SKColor.black, size: CGSize(width: 75, height: 75)) //frame.maxX / 20, height: frame.maxY / 20))
achievementNode.zPosition = -10
achievementNode.name = "AchievementNode"
amount = 0
neededAmount = 10
self.addChild(achievementNode)
self.zPosition = -11
Achievements3.append(achievementNode)
createAchievementLabels()
}
func createAchievementLabels() {
achievementTitleLabel = SKLabelNode(fontNamed: "Avenir-Black")
achievementTitleLabel.fontColor = UIColor.black;
achievementTitleLabel.fontSize = 13 //self.frame.maxY/30
achievementTitleLabel.position = CGPoint (x: 0, y: 45)
achievementTitleLabel.text = "COLLECTOR"
achievementTitleLabel.zPosition = -9
addChild(achievementTitleLabel)
achievementTitleLabel.name = "AchievementTitleLabel"
achievementLabel = SKLabelNode(fontNamed: "Avenir-Black")
achievementLabel.fontColor = UIColor.black;
achievementLabel.fontSize = 13 //self.frame.maxY/30
achievementLabel.position = CGPoint (x: 0, y: -50)
achievementLabel.text = ("\(amount) / \(neededAmount)")
achievementLabel.zPosition = -9
addChild(achievementLabel)
achievementLabel.name = "AmountLabel"
AchievementLabels.append(achievementLabel)
}
func UpdateText() {
achievementLabel.text = ("\(amount) / \(neededAmount)")
}
}
they're are then added in another class called AchievementMenu like so:
for 0...12 {
let Achievement = Achievements()
Achievement.createAchievement()
Achievement.position = CGPoint(x: self.frame.midX, y: self.frame.midY)
Achievement.zPosition = 100
moveableArea.addChild(Achievement)
}
Then in another function in the AchievementMenu class I'm trying to enumerate through the the node tree to be able to update the label to add one to its amount variable and then updates its text like so:
func addOneToAchievementAndUpdateText() {
moveableArea.enumerateChildNodes(withName: "SKNode") {
node, stop in
let LabelAmount:Achievements = node as! Achievements
node.enumerateChildNodes(withName: "AmountLabel") {
node, stop in
LabelAmount.amount += 1
LabelAmount.UpdateText()
}
}
}
but every time i try and cast a variable as an actual class it gives me an error:
Could not cast value of type 'SKLabelNode' (0x10e5edb08) to
'Astrum.Achievements' (0x10c899438).
How do I add one to the amount variable and then update the text so it shows the new amount on the screen?
To avoid the casting error you can check the node type as:
func addOneToAchievementAndUpdateText() {
moveableArea.enumerateChildNodes(withName: "SKNode") {
node, stop in
print("- node type is: \(type(of: node))")
if node is Achievements {
let achievements = node as! Achievements
achievements.amount += 1
achievements.UpdateText()
}
}
}
Your mistake would not have appeared if you put after the line:
Achievement.zPosition = 100
this line:
Achievement.name = "SKNode"
P.S. Don't forget to use lowercase for variables to don't confused these one with class types: generally it's considered as a bad attitude..

Randomize image in array in sprite kit swift.

I was wondering if someone could show me how to make it so that I can spawn random image missiles. Right now I am using one image called "meteor", I have a few more images I would like to show and randomize. I know I need to put them in an array and create an arc for random. I have done it for sound but I'm not sure how to do it for images. This is my code so far.
var lastMissileAdded : NSTimeInterval = 0.0
let missileVelocity : CGFloat = 4.0
func addMissile() {
// Initializing missile node
var missile = SKSpriteNode(imageNamed: "meteor")
missile.setScale(0.44)
// Adding SpriteKit physics body for collision detection
missile.physicsBody = SKPhysicsBody(rectangleOfSize: missile.size)
missile.physicsBody?.categoryBitMask = UInt32(obstacleCategory)
missile.physicsBody?.dynamic = true
missile.physicsBody?.contactTestBitMask = UInt32(shipCategory)
missile.physicsBody?.collisionBitMask = 0
missile.physicsBody?.usesPreciseCollisionDetection = true
missile.name = "missile"
// Selecting random y position for missile
var random : CGFloat = CGFloat(arc4random_uniform(300))
missile.position = CGPointMake(self.frame.size.width + 20, random - 20)
self.addChild(missile)
}
func moveObstacle() {
self.enumerateChildNodesWithName("missile", usingBlock: { (node, stop) -> Void in
if let obstacle = node as? SKSpriteNode {
obstacle.position = CGPoint(x: obstacle.position.x - self.missileVelocity, y: obstacle.position.y)
if obstacle.position.x < 0 {
obstacle.removeFromParent()
}
}
})
}
All you need to do is name them meteor0, meteor1 and meteor2 and use String Interpolation to create your node with your random image:
var missile = SKSpriteNode(imageNamed: "meteor\(arc4random_uniform(3))")