When I try to load my high score and see if the score I just got was bigger, I am getting some problems. First it seems to be adding some of the previous score, making the high score larger. Also, if the score I get is a negative number larger than the high score, it becomes the new high score only positive. Here is my high score view code:
import UIKit
class HighScore: ViewController {
#IBOutlet weak var HighscoreLabel: UILabel!
#IBOutlet weak var Scorelabel: UILabel!
#IBOutlet weak var NewHighscoreLabel: UILabel!
override func viewDidLoad() {
let defaults: NSUserDefaults = NSUserDefaults.standardUserDefaults()
var score = defaults.valueForKey("Score") as? String
Score = score?.stringByTrimmingCharactersInSet(NSCharacterSet.decimalDigitCharacterSet().invertedSet).toInt() ?? 0
Scorelabel.text = score
let SecondDefaults: NSUserDefaults = NSUserDefaults.standardUserDefaults()
var highscore = SecondDefaults.valueForKey("Highscore") as? String
Highscore = highscore?.stringByTrimmingCharactersInSet(NSCharacterSet.decimalDigitCharacterSet().invertedSet).toInt() ?? 0
HighscoreLabel.text = highscore
if Score < 0 {
NewHighscoreLabel.text = ""
}
else if Score > Highscore {
Highscore = 0
Highscore += Score
var HighscoreString:String = String(format: "Highscore:%i", Highscore)
let SecondDefaults: NSUserDefaults = NSUserDefaults.standardUserDefaults()
SecondDefaults.setObject(HighscoreString, forKey: "Highscore")
SecondDefaults.synchronize()
HighscoreLabel.text = highscore
NewHighscoreLabel.text = "New Highscore!"
}
}
}
Here is my saving code for the score on the actual game page:
var ScoreString:String = String(format: "Score:%i", Score)
ScoreLabel.text = (string: ScoreString)
let defaults: NSUserDefaults = NSUserDefaults.standardUserDefaults()
defaults.setObject(ScoreString, forKey: "Score")
defaults.synchronize()
First, some problems in your code: there is no need to create a SecondDefaults variable. It is always the same singleton referring to the defaults data base, so you can continue using your first variable defaults.
Variables, by convention, start with lower case letters. The use of your uppercase letters ivars is very confusing because they look like class names.
The logic is not quite clear because you are retrieving values from user defaults in viewDidLoad and then comparing them and re-setting some values. That does not seem logical. The user defaults entries should be in order when you read them - you should only adjust them when you evaluate a new score.
There are various other illogical lines, e.g.
highscore = 0
highscore += score
is exactly equivalent to
highscore = score
Back to your problem: you should not save your high score as a string. Not surprisingly, you run into all sorts of problems doing that because you have to encode and decode these strings. Instead, store your scores as numbers - you can just use them without having to parse strings.
The error you get is presumably because you have no value in one of the defaults entries. You should initialize your variables upon app start to make sure they are there. The best way to do this is the registerDefaults API.
let seedData = ["Score" : 0, "Highscore" : 0]
defaults.registerDefaults(seedData)
This will initialize them to 0 only if these keys are not already there.
The rest is easy:
let score = defaults.integerForKey("Score")!
scoreLabel.text = "\(score)"
let highscore = defaults.integerForKey("Highscore")!
highscore.text = "\(highscore)"
newHighscoreLabel.text = ""
Note that you can force unwrap with ! because you know the variables are initialized. As pointed out above, reading the score from user defaults does not make any sense. More likely you are displaying a score screen and get a new score value. Thus
defaults.setInteger(score, forKey: "Score")
let highscore = defaults.integerForKey("Highscore")!
if score > highscore {
defaults.setInteger(score, forKey: "Highscore")
newHighscoreLabel.text = "New Highscore!"
}
Related
I would like the label foxmill to store a high score using a user default. Obviously if there is a new high score I would like it to be replaced. The problem is that totalTime (what tracks the score) is a double and not a int. All of the tutorials use a int for the high score tutorial.
import UIKit
class winViewController: UIViewController {
#IBOutlet var score2: UILabel!
#IBOutlet var winningLabel: UILabel!
#IBOutlet var foxMill: UILabel!
#IBOutlet var hhighscore: UILabel!
public var LebelText: String?
public var LebelText2: String?
public var LebelText3: String?
public var LebelText4: String?
override func viewDidLoad() {
super.viewDidLoad()
timeCalculation()
loadState()
}
func saveScore(score: Double) {
// Instantiate user defaults
let userDefaults:UserDefaults = UserDefaults.standard
// Set your score
userDefaults.set(score, forKey: "highScore")
// Sync user defaults
userDefaults.synchronize()
}
func loadState() {
let userDefaults = UserDefaults.standard
let score = userDefaults.double(forKey: "highScore")
foxMill.text = "High Score: \(score)"
}
func timeCalculation(){
guard let unwrapedText = self.LebelText2 else {
return
}
guard let unwrapedText2 = self.LebelText else {
return
}
guard let unwrapedText3 = self.LebelText3 else {
return
}
guard let unwrapedText4 = self.LebelText4 else {
return
}
if let myInt = Double(unwrapedText), let myInt2 = Double(unwrapedText2), let myInt3 = Double(unwrapedText3), let myInt4 = Double(unwrapedText4)
{
var totalTime = myInt + myInt2 + myInt3 + myInt4
self.winningLabel.text = "You won"+"\n"+"Reaction time :" + String(totalTime) + " Seconds"
saveScore(score: totalTime)
}}}
You just save the value with the proper key, then when you retrieve it, make sure to do so as a Double:
func saveScore(score: Double) {
// Instantiate user defaults
let userDefaults:UserDefaults = UserDefaults.standard
// Set your score
userDefaults.set(score, forKey: "highScore")
// Sync user defaults
userDefaults.synchronize()
}
Now when you update your score values, when you say ... (unwrappedText), to make sure you save the user defaults
if let myInt = Double(unwrapedText), let myInt2 = Double(unwrapedText2), let myInt3 = Double(unwrapedText3), let myInt4 = Double(unwrapedText4)
// HERE you do whatever it was you originally did with the text, but also save a value
saveScore(score: myInt)
{
Now the next time you load your app, to load the score:
func loadScore() {
// Instantiate User Defaults
let userDefaults = UserDefaults.standard
let score = userDefaults.double(forKey: "highScore")
}
You really shouldn't name a property "myInt" when you want it to be a Double and not an Integer
If you want your foxMill label to display this high score at load, you want to do two things. First make sure before you app closes at some point you save your state by synchronizing your UserDefaults, look into methods like applicationDidEnterBackground and applicationWillTerminate in your AppDelegate - but that's a little beyond the scope of your question. For now I'll assume you've properly saved your state last time the app quit by calling the saveScore(score:) function I listed above. So now you want to retrieve the score and update your foxMill label at load. You would do something like this:
You could do something like this, by amending the loadScore method above:
func loadScore() {
// Instantiate User Defaults
let userDefaults = UserDefaults.standard
let score = userDefaults.double(forKey: "highScore")
foxMill.text = "High Score: \(score)"
}
And then at the end of viewDidLoad:
override func viewDidLoad() {
super.viewDidLoad()
loadScore()
}
Or you could change the method to return a string which you would then assign to your label's text:
func loadScore() -> String {
// Instantiate User Defaults
let userDefaults = UserDefaults.standard
let score = userDefaults.double(forKey: "highScore")
return "High Score: \(score)"
}
Then in viewDidLoad:
override func viewDidLoad() {
super.viewDidLoad()
foxMill.text = loadScore()
}
I have been working on my xcode project for a couple of weeks now using Xcode and swift. Today when I started running the simulator my highScore was set to 0. This was the first time, it had always kept score. Does this have anything to do with the simulator or is something wrong with my code. I of course don't want the user to use my app if the highScore can reset to 0 at any given time.
class GameScene: SKScene {
let labelHighScore = SKLabelNode()
var highScore = 0
override func didMoveToView(view: SKView) {
var HighscoreDefault = NSUserDefaults.standardUserDefaults()
if(HighscoreDefault.valueForKey("Highscore") != nil) {
highScore = HighscoreDefault.valueForKey("Highscore") as! NSInteger
labelHighScore.text = NSString(format: "%i", highScore) as String
}
labelHighScore.fontSize = 70
labelHighScore.position = CGPointMake(frame.midX, frame.midY + 305)
labelHighScore.fontColor = UIColor.blackColor()
self.addChild(labelHighScore)
}
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
if ball != blackB && ball.texture == blackB.texture {
score += 1
labelScore.text = String(score)
if(score > highScore) {
highScore = score
labelHighScore.text = String(highScore)
var HighscoreDefault = NSUserDefaults.standardUserDefaults()
HighscoreDefault.setValue(highScore, forKey: "Highscore")
HighscoreDefault.synchronize()
}
}
Unless your using the same device it would not keep the same user defaults. If you have always used the simulator they are known to reset from time to time. My suggestions would be to explicitly set the high score's default and run. comment out the code that sets the default and re run. It should maintain that value.
I'm making some great progress with my first iOS game app, currently I'm working on the high score element and if anyone would be so kind as to help guide me how to use the correct code.
I've followed a few tutorials with mixed results, so far I'm increasing the score count by 1 for each screen press (will be changed but using for the purpose for this post), this works fine however I need some help saving both the high score using NSUserDefaults and also displaying the high score.
Below is the extract of my code, currently the score works fine however the high score remains at 0 and doesn't increase. Any help would be appreciated!
Here is my code.....
Thank you.
EDITED WITH REWORKED CODE
// in gameScene:
var scoreLabelNode = SKLabelNode()
var score = NSInteger()
var highScoreLabelNode = SKLabelNode()
var highScore = NSInteger()
// in did move to view
score = 0
scoreLabelNode.fontName = "Helvetica-Bold"
scoreLabelNode.position = CGPoint(x: self.frame.size.width / 2.8, y: self.frame.size.height / 1.2 )
scoreLabelNode.fontSize = 20
scoreLabelNode.alpha = 0.2
scoreLabelNode.zPosition = -30
scoreLabelNode.text = "Score \(score)"
self.addChild(scoreLabelNode)
// start of high score
var highScoreDefault = NSUserDefaults.standardUserDefaults()
if (highScoreDefault.valueForKey("highScore") != nil){
highScore = highScoreDefault.valueForKey("highscore") as! NSInteger!
highScoreLabelNode.text = NSString(format: "highscore : %i", highScore) as String
}
// highScore = 0
// if (score > highScore) {
// highScore = score
// highScoreLabelNode.text = NSString(format: "highscore : %i", highScore) as String
// }
highScoreLabelNode.fontName = "Helvetica-Bold"
highScoreLabelNode.position = CGPoint(x: self.frame.size.width / 2.6, y: self.frame.size.height / 1.3 )
highScoreLabelNode.fontSize = 20
highScoreLabelNode.alpha = 0.2
highScoreLabelNode.zPosition = -30
highScoreLabelNode.text = "High Score \(score)"
self.addChild(highScoreLabelNode)
// in touches began
let incrementScore = SKAction.runBlock ({
++self.score
self.scoreLabelNode.text = "Score \(self.score)"
})
self.runAction(incrementScore)
// in update before each frame
// highScore = 0
if (score > highScore) {
highScore = score
highScoreLabelNode.text = NSString(format: "highscore : %i", highScore) as String
}
To me it seems you dont ever call
if (score > highScore) {
highScore = score
highScoreLabelNode.text = NSString(format: "highscore : %i", highScore) as String
}
again anywhere, which is where your highscore is set? Is it called somewhere that is not indicated in the code you have provided?
From what I can see you are not saving the highscore to User Defaults with NSUserDefaults.standardUserDefaults.setObject(), also, I'm not sure why you are setting highScore to 0
I have a game with three different game modes and a high score screen each in a different view controller. I'm storing the high scores using NSUserDefaults but the values will change throughout the runtime of the application.
The application will save the high scores correctly and when I press clear the scores will all set to 0 and it will show on the screen. If I leave the app and come back the scores will still be zero, but if I replay one of the game modes and return to the high scores screen all the scores will reset to what they where before I cleared them.
Ex: arcade score == 4, easy score == 7, opposite score == 21
I clear the scores and they all are set and show to be zero. Then I play arcade mode and get a score of 6 and return to the high score screen. The values should be (arcade == 6, easy == 0, opposite == 0), but they show to be arcade == 6, easy == 7, opposite == 21.
In one of the GameViewControllers:
func lose(){
// save score
let defaults = NSUserDefaults.standardUserDefaults()
var arcade_score = defaults.integerForKey("arcade")
if(arcade_score < cur+1){ // cur == current level
defaults.setInteger(cur+1, forKey: "arcade")
defaults.synchronize()
}
}
This method is called whenever the player loses the game. This method is similar in each game controller but stores the value in a different key.
In my HighScoreViewController I load and show the values in the viewDidLoad() method and have a button to clear the values:
class HighScoreViewController: UIViewController {
#IBOutlet weak var arcade: UILabel!
#IBOutlet weak var easy: UILabel!
#IBOutlet weak var opposite: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
let defaults = NSUserDefaults.standardUserDefaults()
var arcade_score = defaults.integerForKey("arcade")
var easy_score = defaults.integerForKey("easy")
var opposite_score = defaults.integerForKey("opposite")
arcade.text = String(arcade_score)
arcade.sizeToFit()
easy.text = String(easy_score)
easy.sizeToFit()
opposite.text = String(opposite_score)
opposite.sizeToFit()
}
#IBAction func clearScores(sender: UIButton) {
let defaults = NSUserDefaults.standardUserDefaults()
defaults.setInteger(0, forKey: "arcade")
defaults.setInteger(0, forKey: "easy")
defaults.setInteger(0, forKey: "opposite")
defaults.synchronize()
arcade.text = String(defaults.integerForKey("arcade"))
arcade.sizeToFit()
easy.text = String(defaults.integerForKey("easy"))
easy.sizeToFit()
opposite.text = String(defaults.integerForKey("opposite"))
opposite.sizeToFit()
}
}
What is wrong with my logic?
I am trying to make a high score view. I load the score and high score up and compare the two to see if the score should be set as the new high score. When the score is a negative number, it works fine, but when the number is positive but less than the current high score or bigger than the high score it seems to add the two numbers together. It also seems to subtract 1 from the two? I'm not really sure whats happening. Thanks for the help!
The high score view viewDidLoad (the only code for the view) :
override func viewDidLoad() {
//Load Score
let defaults: NSUserDefaults = NSUserDefaults.standardUserDefaults()
var score = defaults.valueForKey("Score")?.integerValue ?? 0
defaults.synchronize()
Score = score
//Load Highscore
let SecondDefaults: NSUserDefaults = NSUserDefaults.standardUserDefaults()
var highscore = SecondDefaults.valueForKey("Highscore")?.integerValue ?? 0
SecondDefaults.synchronize()
Highscore = highscore
//Set Score Text
ScoreString = String(Score)
Scorelabel.text = ScoreString
//Update Highscore if Score is bigger
if Score > Highscore {
//Set Highscore to Score
Highscore += Score
//Save Highscore
let SecondDefaults: NSUserDefaults = NSUserDefaults.standardUserDefaults()
SecondDefaults.setObject(Highscore, forKey: "Highscore")
SecondDefaults.synchronize()
//Set Highscore Text
HighscoreString = String(Highscore)
HighscoreLabel.text = HighscoreString
NewHighscoreLabel.text = "New Highscore"
}
//Set Highscore Text if Score is smaller
else if Highscore >= Score {
HighscoreString = String(Highscore)
HighscoreLabel.text = HighscoreString
}
}}
Issue is with this code:
Highscore += Score
You are adding HighScore and Score then assigning back to HighScore. Change that to:
Highscore = Score