Martin Jones Martin Jones - 1 month ago 11
Swift Question

SKSpriteNode not working with Random Number Array

I have a SKSpriteNode that is spawn repeatedly. I have created a random number generator and have tried to associate the returns with a different Sprite Image. However, it does not work. The numbers are being generated randomly but even if "2" is returned the SKSpriteNode is drawn as "Fire Barrel 1".

class GameScene: SKScene {

var firstObstacle = SKSpriteNode()
var player = SKSpriteNode()
var randomValue = Int()

override func didMove(to view: SKView) {

createPlayer()

let delay = SKAction.wait(forDuration: 3)
let repeatingAction = SKAction.run(repeatingSequence)
let sequence = SKAction.sequence([ delay, repeatingAction ] )
run(SKAction.repeatForever(sequence))

}

func randomSelector() {
let array = [0, 1, 2, 3]
let randomValue = Int(arc4random_uniform(UInt32(array.count)))
print(array[randomValue])
}

func createPlayer() {
player = SKSpriteNode(imageNamed: "Player")
player.setScale(0.4)
player.position = CGPoint(x: -player.size.width, y: 0)
player.zPosition = 1
addChild(player)
}

func createObstacle() {

if randomValue == 2 {

firstObstacle = SKSpriteNode(imageNamed: "Fire Barrel 2")

}

else {

firstObstacle = SKSpriteNode(imageNamed: "Fire Barrel 1")

}

firstObstacle.position = CGPoint(x: self.frame.width / 2, y: -self.frame.height / 2 + firstObstacle.size.height / 2)
firstObstacle.zPosition = 1
addChild(firstObstacle)
}

func repeatingSequence() {
randomSelector()
createObstacle()

let moveObstacle = SKAction.moveBy(x: -self.frame.width - firstObstacle.size.width, y: 0, duration: 5)
firstObstacle.run(moveObstacle)
}


override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {

}

override func update(_ currentTime: TimeInterval) {

}
}

Answer

Your issue is

let randomValue = Int(arc4random_uniform(UInt32(array.count)))

You are doing what is called "variable shadowing". randomValue also exists at the class instance level, but here because you use let you've declared a local scoped version.

The actual value of self.value is Int() which is 0. Hence why it is "First Barrel l".

The generalized design you're using is not really good. Unless you have some real reason where you need to hold randomValue, you should not make it a class instance variable. Instead pass it by argument.

This would look something like:

func randomSelector() -> Int {
    let array = [0, 1, 2, 3]
    return  Int(arc4random_uniform(UInt32(array.count)))
}

func createObstacle(type:Int) {
    if (type == 2) {
        // Type 2 stuff
    } else {
        // Other stuff
    }

    // Rest of your stuff
}

createObstacle(type: randomSelector())

Although given the nature of how this works, you don't even need the argument, you could just do:

func createObstacle() {
    if (randomSelector() == 2) {
        // Type 2 stuff
    } else {
        // Other stuff
    }

    // Rest of your stuff
}
Comments