0

I have a video game app that I have created in Xcode, SpriteKit with a "Game" template application. My game has a score label that keeps track of the score and is updated when the player scores a point. Below is the code I have created for the two labels which are the current score and the high score. There is a lot more code in my app but I just wanted to simplify it and just show the code that is relevant to this situation. When i close the app down and reopen the app the score resets back to number zero. But what i want is to save the high score number even if you close the app down? And also if the current score is higher than the high score then I want the high score to be updated to the new score if that makes sense.

I'm open to suggestions.

GameScene.h

#import <SpriteKit/SpriteKit.h>

@interface GameScene : SKScene <SKPhysicsContactDelegate>
{
    NSTimer *timerOne;
    NSTimer *timerTwo;
    NSInteger HighScore;
    NSInteger score;
}
@end

GameScene.m

-(void)didMoveToView:(SKView *)view {

   //SCORELABEL
    SKLabelNode *scoreLabel = [SKLabelNode labelNodeWithFontNamed:@"ChalkboardSE-Bold"];
    scoreLabel.position = CGPointMake(CGRectGetMidX(self.frame), self.frame.size.height-50);
    scoreLabel.fontSize = 30;
    scoreLabel.text = @"0";
    scoreLabel.fontColor = [SKColor blueColor];
    scoreLabel.name = @"scoreLabel";
    [self addChild:scoreLabel];
}



-(void) didBeginContact:(SKPhysicsContact *)contact {

   //When redblock comes in contact with redball
   if (contact.bodyA.categoryBitMask == CollisionCategoryRedBlock &&
        contact.bodyB.categoryBitMask == CollisionCategoryRedBall) {

        //Update the score label and add 1 to the current score
        [self addPoint:1];
    }

   //if anything else happens it's gameover
   else {
       [self performGameOver];
   }

}

//Method to add a point to the scorelabel
-(void) addPoint:(NSInteger)points {


    score += points;

    SKLabelNode *scoreLabel = (SKLabelNode*)[self       childNodeWithName:@"scoreLabel"];

    scoreLabel.text =[NSString stringWithFormat:@"%ld", (long)score];

}

//Gameover method which will show the high score label
-(void) performGameOver {

    //HIGHSCORELABEL
    SKLabelNode *highScoreLabel = [SKLabelNode labelNodeWithFontNamed:@"ChalkboardSE-Bold"];
    highScoreLabel.position = CGPointMake(CGRectGetMidX(self.frame), 100);
    highScoreLabel.fontSize = 20;
    highScoreLabel.text = [NSString stringWithFormat:@"High Score: %ld", (long)score];
    highScoreLabel.fontColor = [SKColor blueColor];
    [self addChild:highScoreLabel];
}
mnuages
  • 13,049
  • 2
  • 23
  • 40
Shaun
  • 1
  • 3
  • Could you please provide with an example or perhaps a link to a detailed step by step guide on how to do this ? – Shaun Mar 06 '15 at 18:09

2 Answers2

1

You can either use NSUserDefaults, or if you intend to use device sync and to store bigger ammounts of data, NSCoding.

The easiest and quickest is NSUserDefaults. NSCoding is slightly harder but there are some guided through the net. As for now, NSUSer Defaults would go like this:

Create at implementation a NSUserDefaults:

@implementation FKMyScene{
    NSUserDefaults *prefs;
    /* Any other you use below*/
  }

Then, at init start it like this:

prefs = [[NSUserDefaults alloc] init];
    if(!prefs)
        [prefs setInteger:0 forKey:@"YourAppHighScore"];

Now it should be working and will store value for desired keys. (We setInteger to 0, so initial value is 0. Next, assuming you want to store high scores, you will use a string to name the value (Like "YourAppHighScore") and summon Integer with this name.

/*This should fetch the value whenever you need*/    
[prefs integerForKey:@"YourAppHighScore"];

/*This should update the value whenever you need*/
/*Note that I use setInteger to insert the new value. This can be used anywhere.*/
if(currentScore > [prefs integerForKey:@"YourAppHighScore"])
        [prefs setInteger:currentScore forKey:@"YourAppHighScore"];

If you intend to save anything else, you can do it with the same method, but verify whether you need a integerForKey, objectForKey, etc etc.

Elindor
  • 175
  • 2
  • 8
1

Suppose we have an array of high scores, i.e: Multiple users

Userdefaults, Core Data and Plists can all be read/write but if you use a plist you need to pay attention in what dir you put it. See the plist part down below.

NSUserDefaults:
These are kind of global variables you can say, which don't remove their state until they are destroyed. but can be synchronized

To write them to the userdefaults:

NSArray *stringsArray = [[NSArray alloc] arrayWithObjects: string1, string2, string3, nil];
[[NSUserDefaults standardUserDefaults] setObject:stringsArray forKey:@"MyStrings"];
[[NSUserDefaults standardUserDefaults] synchronize]

To read the from the userdefaults:

NSArray *stringsArray = [[NSUserDefaults standardUserDefaults] objectForKey:@"MyStrings"];

Plist:

If your strings are going to be modified you will need to write and read a plist but you can't write into your app's resources.

  1. To have a read/write plist first find the documents directory

    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *stringsPlistPath = [[paths objectAtIndex:0] stringByAppendingPathComponent:@"Strings.plist"];
    
  2. Create the array (I am assuming the strings are string1, ...)

    NSArray *stringsArray = [[NSArray alloc] arrayWithObjects: string1, string2, string3, nil];
    
  3. write it to file

    [stringsArray writeToFile:stringsPlistPath atomically:YES];
    

To read the plist:

  1. find the documents directory

    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *stringsPlistPath = [[paths objectAtIndex:0] stringByAppendingPathComponent:@"Strings.plist"];
    
  2. read it in:

    NSArray *stringsArray = [NSArray arrayWithContentsOfFile:stringsPlistPath];
    
Majid Bashir
  • 558
  • 1
  • 4
  • 27