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
Related
I know I'm close in getting the getting the score to increment in my game.
When I explicitly change the code to add a integer (5 for example) instead of "%d", the score shows in the HUD when a coin is touched :
func didBeginContact(contact: SKPhysicsContact) {
lblScore.text = String(format: "%d", GameState.sharedInstance.score)
}
to:
func didBeginContact(contact: SKPhysicsContact) {
lblScore.text = String(format: "5", GameState.sharedInstance.score)
}
However if I leave the "%d", then nothing happens. I'm not sure how to increment the score in the HUD or where to make changes.
Here's the rest of the code.
GameScene.swift:
struct PhysicsCategory {
static let None: UInt32 = 0
static let Player: UInt32 = 0b1
static let CoinNormal: UInt32 = 0b1000
static let CoinSpecial: UInt32 = 0b10000
}
class GameScene: SKScene, SKPhysicsContactDelegate {
// HUD
var hudNode: SKNode!
var lblScore: SKLabelNode!
var lblCoins: SKLabelNode!
override func didMoveToView(view: SKView) {
// HUD
hudNode = SKNode()
hudNode.zPosition = 1000
cameraNode.addChild(hudNode)
// Coins
// 1
let coin = SKSpriteNode(imageNamed: "powerup05_1")
coin.position = convertPoint(CGPoint(x: 300, y: self.size.height-100), toNode: cameraNode)
coin.zPosition = 1000
hudNode.addChild(coin)
// 2
lblCoins = SKLabelNode(fontNamed: "ChalkboardSE-Bold")
lblCoins.fontSize = 70
lblCoins.fontColor = SKColor.whiteColor()
lblCoins.position = convertPoint(CGPoint(x: 375, y: self.size.height-100), toNode: cameraNode)
lblCoins.horizontalAlignmentMode = SKLabelHorizontalAlignmentMode.Left
lblCoins.zPosition = 1000
// 3
lblCoins.text = String(format: "X %d", GameState.sharedInstance.coins)
hudNode.addChild(lblCoins)
// Score
// 4
lblScore = SKLabelNode(fontNamed: "ChalkboardSE-Bold")
lblScore.fontSize = 70
lblScore.fontColor = SKColor.whiteColor()
lblScore.position = convertPoint(CGPoint(x: self.size.width-325, y: self.size.height-100), toNode: cameraNode)
lblScore.horizontalAlignmentMode = SKLabelHorizontalAlignmentMode.Right
lblScore.zPosition = 1000
// 5
lblScore.text = "0"
hudNode.addChild(lblScore)
}
}
func didBeginContact(contact: SKPhysicsContact) {
lblScore.text = String(format: "%d", GameState.sharedInstance.score)
}
GameState.swift:
class GameState {
var score: Int
var highScore: Int
var coins: Int
init() {
// Init
score = 0
highScore = 0
coins = 0
// Load game state
let defaults = NSUserDefaults.standardUserDefaults()
highScore = defaults.integerForKey("highScore")
coins = defaults.integerForKey("coins")
}
func saveState() {
// Update highScore if the current score is greater
highScore = max(score, highScore)
score = max(score, highScore)
// Store in user defaults
let defaults = NSUserDefaults.standardUserDefaults()
defaults.setInteger(highScore, forKey: "highScore")
defaults.setInteger(coins, forKey: "coins")
NSUserDefaults.standardUserDefaults().synchronize()
}
class var sharedInstance: GameState {
struct Singleton {
static let instance = GameState()
}
return Singleton.instance
}
}
As I can see you are using GameState.sharedInstance.score to store a score. But you never update it. You have to increment the score each time when player scores. This part:
lblScore.text = String(format: "%d", GameState.sharedInstance.score)
only reads from a score variable.
Also this part doesn't make sense:
highScore = max(score, highScore)
score = max(score, highScore) //remove this
score variable is not the same as highscore variable.
I was able to increment the score by this line:
GameState.sharedInstance.score += 1
Or replace 1 with another number by how many points you want to increment.
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
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!"
}
I have set a high score using NSUserDefaults where if the object makes contact with a block, the game ends. If the score is greater than the high score, it updates the high score with the new value.
How would I reset the high score back to zero with a button?
func didBeginContact(contact: SKPhysicsContact) {
if moving.speed > 0 {
if ( contact.bodyA.categoryBitMask & scoreCategory ) == scoreCategory || ( contact.bodyB.categoryBitMask & scoreCategory ) == scoreCategory {
// Balloon has contact with score entity
score++
scoreLabelNode.text = String(score)
// Add a little visual feedback for the score increment
scoreLabelNode.runAction(SKAction.sequence([SKAction.scaleTo(1.5, duration:NSTimeInterval(0.1)), SKAction.scaleTo(1.0, duration:NSTimeInterval(0.1))]))
} else {
moving.speed = 0
balloon.physicsBody?.collisionBitMask = blockCategory
NSUserDefaults.standardUserDefaults().integerForKey("highscore")
//Check if score is higher than NSUserDefaults stored value and change NSUserDefaults stored value if it's true
if score > NSUserDefaults.standardUserDefaults().integerForKey("highscore")
{
NSUserDefaults.standardUserDefaults().setInteger(score, forKey: "highscore")
NSUserDefaults.standardUserDefaults().synchronize()
}
NSUserDefaults.standardUserDefaults().integerForKey("highscore")
var highscoreShow = defaults.integerForKey("highscore")
highscoreLabelNode = SKLabelNode(fontNamed: "MarkerFelt-Wide")
highscoreLabelNode.position = CGPointMake(CGRectGetMidX(self.frame), 530)
highscoreLabelNode.zPosition = 10
highscoreLabelNode.fontSize = 18
highscoreLabelNode.text = "Highscore: \(highscoreShow)"
self.addChild(highscoreLabelNode)
gameoverLabelNode = SKLabelNode(fontNamed: "MarkerFelt-Wide")
gameoverLabelNode.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame))
gameoverLabelNode.zPosition = 10
gameoverLabelNode.text = "GameOver"
self.addChild(gameoverLabelNode)
returnBtn.position = CGPointMake(CGRectGetMidX(self.frame), 250)
returnBtn.zPosition = 5
returnBtn.setScale(0.5)
self.addChild(returnBtn)
println("end the game")
self.canRestart = true
}
}
}
To reset the high score back to zero all you need to use is:
//Sets the integer value for the key "highscore" to be equal to 0
NSUserDefaults.standardUserDefaults().setInteger(0, forKey: "highscore")
//Synchronizes the NSUserDefaults
NSUserDefaults.standardUserDefaults().synchronize()