0

I am looking for some advice when it comes to saving a score in my app - I currently have a coin count working in which through my HUD class when I collide through Coins the value increases accordingly. My next step is trying to initiate a high-score that initiates, after some research I think the topic I am looking into is based around NSUserDefaults..

The current code :

   import SpriteKit

   class HUD: SKNode {


   //An SKLabelNode to print the coin score:
   let coinCountText = SKLabelNode(text: "000000")


   func createHUDNodes(){

   // Configure the coin text label:
   coinCountText.fontName = "STHupo-Heavy-Italic"
   let coinTextPosition = CGPoint(x: -cameraOrigin.x + 770, y: coinPosition.y)
   coinCountText.position = coinTextPosition

   coinCountText.horizontalAlignmentMode = SKLabelHorizontalAlignmentMode.left
   coinCountText.verticalAlignmentMode = SKLabelVerticalAlignmentMode.center

   // Add the text label and coin icon to the HUD:
   self.addChild(coinCountText)

   }


   func setCoinCountDisplay(newCoinCount:Int) {

   let formatter = NumberFormatter()
   let number = NSNumber(value: newCoinCount)
   formatter.minimumIntegerDigits = 6
   if let coinStr =
        formatter.string(from: number) {

        // Update the label node with the new count:
        coinCountText.text = coinStr
    }
}

Working in the HUD class I think naturally I would need to create another 'SKlabelNode'for the highscore node which I can duplicate from the code that works above.. my problem is how can I implement a highscore feature in the app, as when closed and re-opening the application it will remember the highscore..

I assume the following code would need to be added but I do not understand how it ties together in the class.

     var currentHighScore =  
     NSUserDefaults.standardUserDefaults().integerForKey("coin_highscore")

     var highScoreLabel = SKLabelNode(fontNamed:"STHupo-Heavy-Italic")
     highScoreLabel.text = ""
     highScoreLabel.fontSize = 45
     highScoreLabel.position = CGPoint(x: viewSize.width * 0.5, y: viewSize.height * 0.30)
     self.addChild(highScoreLabel)

     if (score > currentHighScore) {

        NSUserDefaults.standardUserDefaults().setInteger(score, forKey: "player_highscore")
        NSUserDefaults.standardUserDefaults().synchronize()

        highScoreLabel.text = "New High Score: \(score) !"


    } else {

        highScoreLabel.text = "Better Luck Next Time: \(score)"
    }
}

Any advice on how I could integrate this code would be much appreciated.

, AJ


Revised :

     else if nodeTouched.name == "returnToMenu"{
     // Transition to the main menu scene
     self.view?.presentScene(MenuScene(size: self.size),transition.crossFade(withDuration: 0.6))

     let currentHighScore = UserDefaults.standard.integer(forKey: "Player_highscore")

     let highScoreLabel = SKLabelNode(fontNamed:"STHupo-Heavy-Italic")
     highScoreLabel.text = "Value: \ (String(describing: coin.value))"
     highScoreLabel.text = ""
     highScoreLabel.fontSize = 45
     highScoreLabel.zPosition = 100
     highScoreLabel.position = CGPoint(x: 50, y: 50)

     self.addChild(highScoreLabel)

     if (coin.value > currentHighScore) {

     UserDefaults.standard.set(coin.value, forKey: "Player_highscore")

     UserDefaults.standard.synchronize()

     highScoreLabel.text = "New High Value: \(String(describing: coin.value)) !"


     } else {

     highScoreLabel.text = "Better Luck Next Time: \(String(describing: coin.value))"

                            }
                    }
            }

}

I am assuming it's the referencing to my original HUD that is causing the problem? In my coin class I declared the coin.value = 5, each time the coin is collected by coinCountDisplay increases accordingly. However still does not show - :/

AJ James
  • 11
  • 5
  • Don't use `"New High Value: \(String(describing: coin.value)) !"`, use `"New High Value: \(coin.value) !"` instead. – pawello2222 Jun 03 '20 at 11:06

2 Answers2

1

Add a property to your view controller with both get and set and use it in all the places. The get method should get the value from UserDefaults and the set should update the value in UserDefaults.

var coinHighscore: Int {
    get {
        UserDefaults.standard.integer(forKey: "coin_highscore")
    }
    set {
        UserDefaults.standard.set(newValue, forKey: "coin_highscore")
    }
}
Frankenstein
  • 15,732
  • 4
  • 22
  • 47
1

Extending on Frankenstein's answer, IF you want to use Swift 5 you can use Property Wrappers to avoid writing get and set every time:

@propertyWrapper struct UserDefaultsBacked<Value> {
    let key: String
    let defaultValue: Value
    var storage: UserDefaults = .standard

    var wrappedValue: Value {
        get {
            let value = storage.value(forKey: key) as? Value
            return value ?? defaultValue
        }
        set {
            storage.setValue(newValue, forKey: key)
        }
    }
}

And use it like this:

@UserDefaultsBacked(key: "coin_highscore", defaultValue: 0)
var coinHighscore: Int
pawello2222
  • 46,897
  • 22
  • 145
  • 209
  • Hello, thank you for the comments - didn't anticipate for such a quick response! I had been looking at trying the follow at the bottom of my GameScene which doesn't error however I can't see the SKLabelNode appear? : Code revised to follow : – AJ James Jun 02 '20 at 20:39
  • Does the `highScoreLabel` appear on the screen but with the wrong value or is it just not showing? – pawello2222 Jun 02 '20 at 20:47
  • Hello, I've just revised my code in the original post - it's not showing at all... :/ – AJ James Jun 02 '20 at 20:51
  • This means the problem is with your `highScoreLabel` and not with `UserDefaults`. – pawello2222 Jun 02 '20 at 20:56
  • I will amend this first and get back - think I might be able to overcome this as a starting point! Thanks to all for the support so far! :) – AJ James Jun 02 '20 at 22:13
  • Hello - Right, I've revised this within my GameOver function in which the SKLabelNode appears fine. :) I adjusted the the highScoreLabel.text = "000000" It does not however update a score duirng gameplay. I am wondering if it's not picking up the coin value.. Within the coin class I have set the var = 5 I don't suppose you would be able to direct me to any resources you may have come across on this topic? :) Thanks again! – AJ James Jun 03 '20 at 09:59
  • You can try some debug printing to see what are the exact values of your variables (`currentHighScore`, `coin.value`...). But this question was about `UserDefaults`(hope we answered your issues). Please create another question if you have problems with displaying the coin value - I'll be happy to help you there. – pawello2222 Jun 03 '20 at 11:18