This is the first of my improvements to the SlippyFlippy penguin game. While this may not make sense since I have not posted all the game code yet, it might help those trying to come up with some of these solutions for their own games. While playing against some of my friends on our different devices, we found we need a different score for the hard mode and easy mode. In the hard mode, the game ends if the penguin contacts the top or bottom walls. In the easy mode the penguin bounces off the top and bottom walls.
There is a bit of a real estate problem about putting two scores on the screen. The solution is to fade in one high score, then fade it out, then fade the other one in, then fade that one out. This repeats forever.
My current code for changing the label looks like this:
highScoreLabel.text = [NSString stringWithFormat:@"High Score: %li",(long)highScore];
It’s just setting the labels text. This shows up at setup and game over. Since it shows up in two places, I’ll make a method for the animation. Before I do, I need to find and store the high score. I look at the game over code in update:
if (highScore < score ){ highScore = score; highScoreLabel.text = [NSString stringWithFormat:@"High Score: %li",(long)highScore]; NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; [defaults setInteger:highScore forKey:@"highScore"]; [defaults synchronize]; }
If we have a high score, we do two things. We first display the new high score, and secondly we save the new high score to NSUserDefaults
. I introduced an new NSInteger
called highScoreHard
. With this addition, there are two situations instead of one where we need to process a high score, so the if has to reflect both:
if ((highScore < score && isEasyMode) || (highScoreHard < score && !isEasyMode)){
The BOOL
isEasyMode
is set when we select the mode we want to use. If we are in easy mode and there is a new high score, or if we are in hard mode and we have a new high score, we need to post a new high score. We can now use isEasyMode
to post the score to the right place:
if (isEasyMode) highScore = score; else highScoreHard = score;
Our last change to the game over code is to add another key entry to the NSUserDefaults
entries under defaults
.
[defaults setInteger:highScoreHard forKey:@"highScoreHard"]; If we stub our animation method in makeHighScoreAnimate for the moment, this snippet of code changes to: if ((highScore < score && isEasyMode) || (highScoreHard < score && !isEasyMode)){ if (isEasyMode) highScore = score; else highScoreHard = score; [self makeHighScoreAnimate]; NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; [defaults setInteger:highScore forKey:@"highScore"]; [defaults setInteger:highScoreHard forKey:@"highScoreHard"]; [defaults synchronize]; }
We now need to read the high scores when we start the app in initwithSize:
. We have another entry in defaults with a new key. That segment of code in initwithSize:
looks like this now:
//grab the last high score from persistent memory NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; highScore = [defaults integerForKey:@"highScore"]; highScoreHard = [defaults integerForKey:@"highScoreHard"]; [self makeHighScoreAnimate];
We have one more thing to do and that is make the animation code.
-(void)makeHighScoreAnimate{ //remove the old high score animation, if there [highScoreLabel removeActionForKey:@"highScoreAnimate"]; //makes strings for the two scores NSString *highScoreLabelText = [NSString stringWithFormat:@"Easy High: %li",(long)highScore]; NSString *highScoreLabelHardText = [NSString stringWithFormat:@"Hard High: %li",(long)highScoreHard]; //Create the animation sequence and run it forever. SKAction *highScoreAnimateSequence = [SKAction sequence:@[ [SKAction runBlock:^{highScoreLabel.text = highScoreLabelText;}], [SKAction fadeInWithDuration:1.00], [SKAction waitForDuration:3.0], [SKAction fadeOutWithDuration:1.0], [SKAction runBlock:^{highScoreLabel.text = highScoreLabelHardText;}], [SKAction fadeInWithDuration:1.00], [SKAction waitForDuration:3.0], [SKAction fadeOutWithDuration:1.0], ]]; SKAction *highScoreAnimate = [SKAction repeatActionForever:highScoreAnimateSequence]; //put the action in the label [highScoreLabel runAction:highScoreAnimate withKey:@"highScoreAnimate"]; }
We remove the old high score first. If there is no SKaction there, it will do nothing. To make the coding easier to read, we make two strings highScoreLabelText and highScoreLabelHardText to hold the two high scores and titles. We make an SKAction sequence, which is an array of SKActions. If you have something other than an SKAction that you want to do, you can add it in a runBlock: method, as we did with changing the titles. I then take the sequence and repeat it forever.
I run the SKAction to the highScoreLabel and give it a key so I can remove it when I need to change it. Now when I build and run, the two high scores fade in and out.
Leave a Reply