Martin Jones
Martin Jones

Reputation: 123

Swift 3 Update Label Node with Incrementing Integer

I am new to coding, so be kind. I am creating a game in Swift 3, similar to Flappy Bird, and am having a problem with my score node. I have created a Label Node for the score but when the player contacts the scoreDetect node no score is added. I can't work out whether I've coded the section that adds a point incorrectly or whether my physics code is incorrect. Any help is appreciated. Thanks.

import SpriteKit
import GameplayKit

struct PhysicsCategory {

static let player : UInt32 = 0x1 << 1
static let roof : UInt32 = 0x1 << 2
static let floor : UInt32 = 0x1 << 3
static let lowerObstacle : UInt32 = 0x1 << 4
static let upperObstacle : UInt32 = 0x1 << 5
static let scoreDetect : UInt32 = 0x1 << 6

}

class GameScene: SKScene, SKPhysicsContactDelegate {

var bgColor = UIColor(red: 39/255, green: 41/255, blue: 56/255, alpha: 1.0)
var roof = SKSpriteNode()
var floor = SKSpriteNode()
var lowerObstacle = SKSpriteNode()
var upperObstacle = SKSpriteNode()
var player = SKSpriteNode()
var randomValue = Int()
var scoreDetect = SKSpriteNode()
var scoreLabel = SKLabelNode()
var scoreValue = Int()
var logo = SKSpriteNode()
var gameStarted = Bool()

override func didMove(to view: SKView) {

        createPlayer()
        createTiles()
        createScoreLabel()

        physicsWorld.contactDelegate = self
        self.physicsWorld.gravity = CGVector(dx: 0.0, dy: -4.0)
        backgroundColor = bgColor

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

}

// Random Selector For Obstacles

func randomSelector() -> Int {

    let array = [1, 2, 3]
    return  Int(arc4random_uniform(UInt32(array.count)))

}

// Player Rules

func createPlayer() {

    player = SKSpriteNode(imageNamed: "Player")
    player.setScale(0.4)
    player.position = CGPoint(x: -player.size.width, y: 0)
    player.zPosition = 2
    addChild(player)

    player.physicsBody = SKPhysicsBody(texture: SKTexture(imageNamed: "Player"), size: player.size)
    player.physicsBody?.categoryBitMask = PhysicsCategory.player
    player.physicsBody?.collisionBitMask = PhysicsCategory.roof | PhysicsCategory.floor | PhysicsCategory.upperObstacle | PhysicsCategory.lowerObstacle | PhysicsCategory.scoreDetect
    player.physicsBody?.contactTestBitMask = PhysicsCategory.roof | PhysicsCategory.floor | PhysicsCategory.upperObstacle | PhysicsCategory.lowerObstacle | PhysicsCategory.scoreDetect
    player.physicsBody?.allowsRotation = false
    player.physicsBody?.affectedByGravity = true
    player.physicsBody?.isDynamic = false

}

// Create Background

func createTiles() {

    roof = SKSpriteNode(imageNamed: "Roof")
    roof.position = CGPoint(x: 0, y: self.frame.height / 2 - roof.size.height / 2)
    roof.zPosition = 1
    addChild(roof)

    roof.physicsBody = SKPhysicsBody(texture: SKTexture(imageNamed: "Roof"), size: roof.size)
    roof.physicsBody?.categoryBitMask = PhysicsCategory.roof
    roof.physicsBody?.collisionBitMask = PhysicsCategory.player
    roof.physicsBody?.contactTestBitMask = PhysicsCategory.player
    roof.physicsBody?.allowsRotation = false
    roof.physicsBody?.affectedByGravity = false
    roof.physicsBody?.isDynamic = false

    floor = SKSpriteNode(imageNamed: "Floor")
    floor.position = CGPoint(x: 0, y: -self.frame.height / 2)
    floor.zPosition = 1
    addChild(floor)

    floor.physicsBody = SKPhysicsBody(texture: SKTexture(imageNamed: "Floor"), size: floor.size)
    floor.physicsBody?.categoryBitMask = PhysicsCategory.floor
    floor.physicsBody?.collisionBitMask = PhysicsCategory.player
    floor.physicsBody?.contactTestBitMask = PhysicsCategory.player
    floor.physicsBody?.allowsRotation = false
    floor.physicsBody?.affectedByGravity = false
    floor.physicsBody?.isDynamic = false

}

// Obstacle Spawn Rules

func createObstacle() {

    if (randomSelector() == 1) {
        lowerObstacle = SKSpriteNode(imageNamed: "Fire Barrel 1")
        upperObstacle = SKSpriteNode(imageNamed: "Fire Barrel 3")
        scoreDetect = SKSpriteNode(color: UIColor.red, size: CGSize(width: 32, height: frame.height))

        upperObstacle.position = CGPoint(x: self.frame.width / 2 + upperObstacle.size.width / 2, y: self.frame.height / 2 - upperObstacle.size.height / 2 + 12)
        lowerObstacle.position = CGPoint(x: self.frame.width / 2 + lowerObstacle.size.width / 2, y: -self.frame.height / 2 + lowerObstacle.size.height - 15)
        scoreDetect.position = CGPoint(x: self.frame.width / 2 + upperObstacle.size.width, y: 0)
    }
    else {
        if (randomSelector() == 2) {
            lowerObstacle = SKSpriteNode(imageNamed: "Fire Barrel 2")
            upperObstacle = SKSpriteNode(imageNamed: "Fire Barrel 2")
            scoreDetect = SKSpriteNode(color: UIColor.red, size: CGSize(width: 32, height: frame.height))

            upperObstacle.position = CGPoint(x: self.frame.width / 2 + upperObstacle.size.width / 2, y: self.frame.height / 2 - upperObstacle.size.height / 1.9)
            lowerObstacle.position = CGPoint(x: self.frame.width / 2 + lowerObstacle.size.width / 2, y: -self.frame.height / 2 + lowerObstacle.size.height / 1.5)
            scoreDetect.position = CGPoint(x: self.frame.width / 2 + upperObstacle.size.width, y: 0)
        }
        else {
            lowerObstacle = SKSpriteNode(imageNamed: "Fire Barrel 3")
            upperObstacle = SKSpriteNode(imageNamed: "Fire Barrel 1")
            scoreDetect = SKSpriteNode(color: UIColor.red, size: CGSize(width: 32, height: frame.height))

            upperObstacle.position = CGPoint(x: self.frame.width / 2 + upperObstacle.size.width / 2, y: self.frame.height / 2 - upperObstacle.size.height / 1.5 + 4)
            lowerObstacle.position = CGPoint(x: self.frame.width / 2 + lowerObstacle.size.width / 2, y: -self.frame.height / 2 + lowerObstacle.size.height / 1.75 + 7)
            scoreDetect.position = CGPoint(x: self.frame.width / 2 + upperObstacle.size.width, y: 0)
        }
    }

    lowerObstacle.zPosition = 2
    lowerObstacle.setScale(0.8)

    lowerObstacle.physicsBody = SKPhysicsBody(rectangleOf: lowerObstacle.size)
    lowerObstacle.physicsBody?.categoryBitMask = PhysicsCategory.lowerObstacle
    lowerObstacle.physicsBody?.collisionBitMask = PhysicsCategory.player
    lowerObstacle.physicsBody?.contactTestBitMask = PhysicsCategory.player
    lowerObstacle.physicsBody?.allowsRotation = false
    lowerObstacle.physicsBody?.affectedByGravity = false
    lowerObstacle.physicsBody?.isDynamic = false

    upperObstacle.zPosition = 2
    upperObstacle.setScale(0.8)

    upperObstacle.physicsBody = SKPhysicsBody(rectangleOf: upperObstacle.size)
    upperObstacle.physicsBody?.categoryBitMask = PhysicsCategory.upperObstacle
    upperObstacle.physicsBody?.collisionBitMask = PhysicsCategory.player
    upperObstacle.physicsBody?.contactTestBitMask = PhysicsCategory.player
    upperObstacle.physicsBody?.allowsRotation = false
    upperObstacle.physicsBody?.affectedByGravity = false
    upperObstacle.physicsBody?.isDynamic = false

    scoreDetect.physicsBody?.categoryBitMask = PhysicsCategory.scoreDetect
    scoreDetect.physicsBody?.collisionBitMask = PhysicsCategory.player
    scoreDetect.physicsBody?.contactTestBitMask = PhysicsCategory.player
    scoreDetect.physicsBody?.allowsRotation = false
    scoreDetect.physicsBody?.affectedByGravity = false
    scoreDetect.physicsBody?.isDynamic = false

    addChild(lowerObstacle)
    addChild(upperObstacle)
    addChild(scoreDetect)
    lowerObstacle.run(
        SKAction.sequence([
            SKAction.wait(forDuration: 6),
            SKAction.removeFromParent()
        ])
    )
    upperObstacle.run(
        SKAction.sequence([
            SKAction.wait(forDuration: 6),
            SKAction.removeFromParent()
        ])
    )
    scoreDetect.run(
        SKAction.sequence([
            SKAction.wait(forDuration: 6),
            SKAction.removeFromParent()
            ])
    )
}

// Create Spawn and Move Sequence

func repeatingSequence() {

    createObstacle()
    let moveLowerObstacle = SKAction.moveBy(x: -self.frame.width - lowerObstacle.size.width * 2, y: 0, duration: 5)
    lowerObstacle.run(moveLowerObstacle)
    let moveUpperObstacle = SKAction.moveBy(x: -self.frame.width - upperObstacle.size.width * 2, y: 0, duration: 5)
    upperObstacle.run(moveUpperObstacle)
    let moveScoreDetect = SKAction.moveBy(x: -self.frame.width - upperObstacle.size.width * 2, y: 0, duration: 5)
    scoreDetect.run(moveScoreDetect)

}

func createScoreLabel() {

    scoreLabel = SKLabelNode(fontNamed: "Arial")
    scoreLabel.fontSize = 22
    scoreLabel.position = CGPoint(x: 305, y: -638)
    scoreLabel.horizontalAlignmentMode = .center
    scoreLabel.verticalAlignmentMode = .center
    scoreLabel.text = "SCORE: \(scoreValue)"
    scoreLabel.fontColor = UIColor.white
    scoreLabel.zPosition = 4

    addChild(scoreLabel)

}

func didBegin(_ contact: SKPhysicsContact) {
    let firstBody = contact.bodyA
    let secondBody = contact.bodyB

    if firstBody.categoryBitMask == PhysicsCategory.scoreDetect && secondBody.categoryBitMask == PhysicsCategory.player || firstBody.categoryBitMask == PhysicsCategory.player && secondBody.categoryBitMask == PhysicsCategory.scoreDetect {
            scoreValue += 1
    }
}

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

    player.physicsBody?.isDynamic = true
    let impulse = CGVector(dx: 0, dy: 200)
    player.physicsBody?.velocity = CGVector(dx: 0, dy: 0)
    player.physicsBody?.applyImpulse(impulse)

}

override func update(_ currentTime: TimeInterval) {

}

}

Upvotes: 0

Views: 143

Answers (1)

Luca Angeletti
Luca Angeletti

Reputation: 59536

You are properly updating the scoreValue property. However you also need to update what is shown inside the scoreLabel accordingly to the new value of scoreValue.

So replace this

var scoreValue = Int()

with this

var scoreValue = Int() {
    didSet {
        scoreLabel.text = self.scoreValue.description
    }
}

Now every time scoreValue changes, the scoreLabel is updated automatically.

Upvotes: 3

Related Questions