Advertisement

iOS SDK: Game Center Achievements and Leaderboards - Part 2

by

Welcome to the second and final part of the Game Center Tutorial Series. In this tutorial, we will integrate the achievements and leaderboards created with iTunesConnect during part 1 with Objective-C and Xcode.

Step 1: Building the Interface

Before we start with Interface Builder, we first set need to setup some outlets and actions. Open Game_CenterViewController.h and modify the code to read as follows:

#import <UIKit/UIKit.h>
#import <GameKit/GameKit.h>

#import "GameCenterManager.h"


@class GameCenterManager;

@interface Game_CenterViewController : UIViewController <UIActionSheetDelegate, GKLeaderboardViewControllerDelegate, GKAchievementViewControllerDelegate, GameCenterManagerDelegate> {
	
	
	GameCenterManager *gameCenterManager;
	
	int64_t  currentScore;
	
	NSString* currentLeaderBoard;
	
	IBOutlet UILabel *currentScoreLabel;

}

@property (nonatomic, retain) GameCenterManager *gameCenterManager;
@property (nonatomic, assign) int64_t currentScore;
@property (nonatomic, retain) NSString* currentLeaderBoard;
@property (nonatomic, retain) UILabel *currentScoreLabel;


- (IBAction) reset;
- (IBAction) showLeaderboard;
- (IBAction) showAchievements;
- (IBAction) submitScore;
- (IBAction) increaseScore;


- (void) checkAchievements;

@end

First, we import the GameKit framework and the GameCenterManager class. Then, we declare the GameCenterManager class, so we can declare an instance of that class in the @interface. After that we declare the following delegates:

        
  • UIActionSheetDelegate (to use an action sheet)
  • GKLeaderboardViewControllerDelegate (to show the leaderboard in our app)
  • GKAchievementViewControllerDelegate (to show the achievements in our app)
  • GameCenterManagerDelegate (to use the GameCenterManager delegate)

In the @interface we declare some instances and after that we create some actions. Press CMD + S to save the project.

In the “Game Center” folder in the “Project Navigator” click on Game_centerViewController.xib.

Select the View window and choose the background you prefer. I chose “Scroll View Textured Background Color”. Drag 5 “Round Rect Buttons” from the Library to the view. Name and arrange them as shown below. Also drag 2 “Labels” from the Library to the view. Name the first one “Current Score:” and delete the text of the second label.

    Interface

Select “File’s owner” and open the Connections Inspector.

    File’s Owner

Connect the actions to the associated buttons, by dragging them to the buttons and select “Touch Up Inside” from the menu.

    Select Touch Up Inside
    Connections Inspector

Drag the “CurrentScoreLabel” outlet to the label with no text and now we are done with the interface.

Step 2: Edit AppSpecificValues.h

Open AppSpecificValues.h and modify the code to read as follows:

//Leaderboard Category IDs
#define kLeaderboardID @"1"

//Achievement IDs
#define kAchievementOneTap @"1_Tap"
#define kAchievement20Taps @"20_Taps"

Here we create the constants for our leaderboard and our achievements. As you can see are the ID’s the same as the ones we created in iTunes Connect.

Step 3: Edit Game_CenterViewController.m

First, we are going to synthesize our instances and release them. We also import the “AppSpecificValues” and “GameCenterManager” classes. So open Game_CenterViewController.m and modify the code at the top of the page as follows:

#import "Game_CenterViewController.h"
#import "AppSpecificValues.h"
#import "GameCenterManager.h"

@implementation Game_CenterViewController

@synthesize gameCenterManager;
@synthesize currentScore;
@synthesize currentLeaderBoard;
@synthesize currentScoreLabel;

Now modify the viewDidUnload and dealloc methods as follows:

- (void)viewDidUnload
{
    [super viewDidUnload];
    // Release any retained subviews of the main view.
    // e.g. self.myOutlet = nil;
    
    self.gameCenterManager = nil;
    self.currentLeaderBoard = nil;
    self.currentScoreLabel = nil;
}


- (void)dealloc {
    [gameCenterManager release];
    [currentLeaderBoard release];
    [currentScoreLabel release];
    [super dealloc];
}

Step 4: Signing in to Game Center

Scroll down to the “viewDidLoad” method, uncommend it and modify the code as follows:

- (void)viewDidLoad {
    [super viewDidLoad];
	
	self.currentLeaderBoard = kLeaderboardID;
	self.currentScore = 0;
	
	if ([GameCenterManager isGameCenterAvailable]) {
		
		self.gameCenterManager = [[[GameCenterManager alloc] init] autorelease];
		[self.gameCenterManager setDelegate:self];
		[self.gameCenterManager authenticateLocalUser];
		
		
	} else {
		
		// The current device does not support Game Center.
				
	}

}

First we set our currentLeaderboard to our leaderBoard we created in iTunes Connect. After that we set our currentscore to 0. Your high score in Game Center won’t be set to zero, because it only submit scores higher than the previous one. Then we look if Game Center is available on the device the application is running. If Game Center is available we authenticate the local user. If Game Center is not available, nothing happens. You can tell the user that Game Center is not available with a alertview, but I leave it with a comment.

Now you can test your project. Press CMD + R to build and run it. You will get some warnings, but the app will run. If you are already logged in to Game Center, you get the following message: Welcome Back, “Game Center Name”. If you where not logged in to Game Center you get an alert view with the options to create a new account, sign in to an existing account or cancel. If you cancel the leaderboard and achievements won’t work, because you are not signed in to Game Center. The buttons won’t work, because we haven’t made the actions in Xcode.

    Sign in to Game Center

Step 5: Showing the Leaderboards and Achievements

If you used the simulator, close it and go back to Xcode. Add the following code under the viewDidLoad method:

- (IBAction) showLeaderboard
{
	GKLeaderboardViewController *leaderboardController = [[GKLeaderboardViewController alloc] init];
	if (leaderboardController != NULL) 
	{
		leaderboardController.category = self.currentLeaderBoard;
		leaderboardController.timeScope = GKLeaderboardTimeScopeWeek;
		leaderboardController.leaderboardDelegate = self; 
		[self presentModalViewController: leaderboardController animated: YES];
	}
}

- (void)leaderboardViewControllerDidFinish:(GKLeaderboardViewController *)viewController
{
	[self dismissModalViewControllerAnimated: YES];
	[viewController release];
}

- (IBAction) showAchievements
{
	GKAchievementViewController *achievements = [[GKAchievementViewController alloc] init];
	if (achievements != NULL)
	{
		achievements.achievementDelegate = self;
		[self presentModalViewController: achievements animated: YES];
	}
}

- (void)achievementViewControllerDidFinish:(GKAchievementViewController *)viewController;
{
	[self dismissModalViewControllerAnimated: YES];
	[viewController release];
}

Here, we creae the actions to show the leaderboard and the achievements. We also create 2 methods to go back. The first actions is to show the leaderboard. As you can see we set the timeScope to GKLeaderboardTimeScopeWeek. This means that the leaderboard section is set to “This Week”. There are 3 time scopes and they are straight forward:

        
  • GKLeaderboardTimeScopeToday
  • GKLeaderboardTimeScopeWeek
  • GKLeaderboardTimeScopeAllTime

If you build and run again, the “Show Leaderboard” and “Show Achievements” buttons will work. Now you can see the Achievements we have created and the associating descriptions and point values. As you can see the leaderbord section is “This Week”. By changing the Time Scope in Xcode you can set the default section to “All Time” or “Today”. The leaderboard says “No Scores”, because we never submitted a score for this leaderboad. Click Done to dismiss the Game Center view.

    Game Cente Achievements & leaderboard

Step 6: Handle the Score and Achievements

Add the following code under the code we just created:

- (IBAction) increaseScore
{
	self.currentScore = self.currentScore + 1;
	currentScoreLabel.text = [NSString stringWithFormat: @"%ld", self.currentScore];
	
	[self checkAchievements];
}

Here we create a action to increase your currentScore. We also update our label to the currentScore and call the checkAchievements function to see if we achieved an achievement.

- (void) checkAchievements
{
	NSString* identifier = NULL;
	double percentComplete = 0;
	switch(self.currentScore)
	{
		case 1:
		{
			identifier= kAchievementOneTap;
			percentComplete= 100.0;
			break;
		}
		case 5:
		{
			identifier= kAchievement20Taps;
			percentComplete= 25.0;
			break;
		}
		case 10:
		{
			identifier= kAchievement20Taps;
			percentComplete= 50.0;
			break;
		}
		case 15:
		{
			identifier= kAchievement20Taps;
			percentComplete= 75.0;
			break;
		}
		case 20:
		{
			identifier= kAchievement20Taps;
			percentComplete= 100.0;
			break;
		}
		
	}
	if(identifier!= NULL)
	{
		[self.gameCenterManager submitAchievement: identifier percentComplete: percentComplete];
	}
}

In this function we look if we achieved an achievement with a switch statement.
First we create a NSString and a double to store our values. In the switch statement we check if the currentscore is 1, 5, 10, 15 or 20. After the switch statement we look if there is something stored in the NSString we created. If there was something stored to that NSString we submit the achievement. We also submit an achievement if you completed it partly. For example, if you tapped the button 10 times you ate on 50% of the “20 Taps” achievement.

We also want to submit or high score, so add the following actions under the code we just created:

- (IBAction) submitScore
{
	if(self.currentScore > 0)
	{
		[self.gameCenterManager reportScore: self.currentScore forCategory: self.currentLeaderBoard];
	}
}

Here we check if the score is higher than 0, because we don’t want a score of 0 to be submitted. We submitted our currentScore for our currentLeaderboard.

Build and run the application again and now you can increase your score and submit it. If you click the button 15 times and go to “Show Achievements” you can see that you achieved the “1 Tap” and are on 75% of the “20 Taps” achievement. The Description of the “1 Tap” achievement also changed in the text we gave it when it in iTunes Connect for when it was earned. Close the achievements view and click “Submit Score”, after that click “Show Leaderbaord”. Now you see your score (if your currentScore was higher than 0).

    Game Cente Achievements & leaderboard

Step 7: Reset the Score and Achievements

dd the following code under the code we just created:

- (IBAction) reset
{
	UIActionSheet *actionSheet = [[UIActionSheet alloc] initWithTitle:@"Are you sure you want to reset your score and achievements?"
															 delegate:self
													cancelButtonTitle:@"Cancel" 
											   destructiveButtonTitle:@"Reset" 
													otherButtonTitles:nil];
	[actionSheet showInView:[self view]];
	[actionSheet release];
	
}

Here we created a action sheet in the reset action. We set the delegate to “self” because we want to do something if you clicked the “reset” button.

Under the “reset” action add the following code:

- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex
{
	if (buttonIndex == 0) {
		
		[gameCenterManager resetAchievements];
		
		self.currentScore = 0;
		currentScoreLabel.text = [NSString stringWithFormat: @"%ld", self.currentScore];

	}
}

In this code we look witch button you clicked. You can’t edit the “Cancel” button so we start at a buttonIndex of 0. If you clicked the “Reset” button in the action sheet, the gameCenterManager resets your achievements, the currentScore is set to 0 and we update the currentScoreLabel text.

Step 8: Notify the User of Earned Achievement

Add the following code under the code we just created:

- (void) achievementSubmitted: (GKAchievement*) ach error:(NSError*) error;
{

	if((error == NULL) && (ach != NULL))
	{
		if (ach.percentComplete == 100.0) {
			UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Achievement Earned!" 
															  message:(@"%@",ach.identifier)
															 delegate:nil 
													cancelButtonTitle:@"OK" 
													otherButtonTitles:nil];
			[alert show];
			[alert release];
		}
		
	}
	else
	{
		// Achievement Submission Failed.
	
	}

}

First we check if there wasn’t an error and if there is something stored in “ach”. If this is both true, then we check if ach.presentComplete is 100.0, because we only want to give the user a message if he earned a achievement and not if he is on 50% of an achievement.
If that is true, we show the user that he earned an achievement with an alert view. We set delegate to nil of this alert view, because we don’t need it, we only use the cancel button.

If there was an error or there was nothing stored in ach, then you can give the user an message that the achievement submission failed, but I leave it with a comment.

Build and Run to finish the tutorial. To check if the reset button and the alert view work, click the “Reset Achievements & Score” button. Then increase the score and a alert view should show.

    Achievement Earned

If you earned both achievements and close the app and the delete if from the multitask bar, the currentScore is set to 0 again, because we didn’t store that value. If you increase the score, or apps thinks that you earned the “1 Tap” achievement again, but you already earned it. If you want to occur this, you can save the currentScore value.

Thanks for reading this tutorial about Game Center. If you have questions or comments on this tutorial, leave them in the comments section below or mail me at ballgameios@gmail.com

Advertisement