Research Group for Applied Software Engineering
Forschungsgruppe für Angewandte Softwaretechnik

iOS Game Center Tutorial

Tutorial written by Alvin Stanescu, Technische Universität München

Game Center

Introduction

Game Center, Apple's Social Gaming Network, was introduced on 8.09.2010. The first iOS version to support Game Center was iOS 4.1, meaning the iPhone 2G and the iPod Touch 1st Generation do not support Game Center, while the other iOS devices, besides the iPhone 3G, are all able to support Game Center when running iOS 4.1 or later. The first OS X version to support Game Center was Mountain Lion, which launched on 25.07.2012.

With iOS 7, Apple introduce a couple of new features, among which the most important is Leaderboard Sets, and important API changes.

Game Center can be used by players to track their in-game achievements, their high scores on different leaderboards and to be able to play together, either in a direct way (turn-based games, multiplayer games) or in an indirect way (challenges).

Motivation

"We do not stop playing because we grow old, we grow old because we stop playing!" Benjamin Franklin

This quite by Benjamin Franklin reflects on how playing games affects people's mental capacities. It is common for old people, who are still active and in good mental shape, to play some sort of game, be it a sports game, board game or just doing crosswords.

 

Why should you use Game Center?

  • People love to play games and be social at the same time, especially playing with friends and talking to them about it
  • It helps with keeping players involved in your game even after completing most of it, therefore resulting in possibly better revenues for the game developers and increased popularity since the players might want to show the game to their friends since they've worked hard on achieving something in this game
  • Unified social system for iOS, unlike other solutions, e.g. OpenFeint, which was a popular Social Gaming Platform on iOS before the launch of Game Center
  • It is extremely easy to integrate Game Center into an already developed game and it increases the audience of your game, since players might look on Game Center at what games their friends are playing
  • It helps the player keep track of what he has achieved within a game and gives him more reasons to play further

Example Applications

Temple Run

  

Introduced in August 2011, Temple Run's popularity has been soaring ever since, with multiple versions of the game being introduced. The original version's strong point was its very well implemented Game Center integration. Many sorts of achievements are available, ranging from easy to extremely hard and almost-impossible achievements. The high score multiplier also increases the more achievements a player has, therefore increasing the amount of dedication to be able to achieve greatness in Temple Run.

Fruit Ninja

Introduced in April 2010, initially with OpenFeint support, adding Game Center with the release of iOS 4.1, Fruit Ninja is one of the most popular iOS games ever. There are many sorts of achievements, some easy to accomplish, some which require a lot of dedication, while others require doing something special in the game. They have improved the repeatability of the game drastically, since players want to compete with their friends in completing theses achievements or beating their friends' high scores.

Overview

To manage Game Center-related operations in iOS and OS X we use Apple's GameKit Framework, included in the iOS SDK starting with version 4.1 and in the OS X SDK starting with version 10.8 (Mountain Lion). Apple says of Game Center that it "allows a player’s devices to connect to the Game Center service and exchange information". What Game Center essentially does is it persisting player and game data on its servers and delivering it to devices upon request.

The process of configuring the app for Game Center integration, authenticating the user and integrating the game with Game Center is explained in detail further.

App Configuration & Management 

To be able to integrate an app with Game Center, a paid developer account is needed!

If you do not have a paid developer account, you can register at http://developer.apple.com.

 

Creating an App ID

In the iOS Provision Portal click on New App ID and configure the common name of the application and the bundle identifier, which is used to connect to Game Center. The bundle identifier should be in reverse-DNS notation (e.g. com.apple.calendarApp).

 

Adding a new app

In iTunes Connect, under Manage Your Applications we create a new app and use the previously created bundle identifier. The App Name is the display name of our application and the SKU Number is a unique ID for your app, used only by iTunes.

Afterwards, pricing, version and availability need to be configured in the following steps. Icons need to be provided by the application.

 

Enabling Game Center

Once the app is created, we need to enable Game Center for it in iTunes Connect. To do this, go to Manage Your Apps -> Your App -> Manage Game Center and activate Game Center. That is all you need at the moment, we will add achievements and leaderboards further on in the tutorial.

In the Xcode project's properties, under General in the target settings, add the bundle identifier and link with the GameKit Framework.

 

Tip: Make sure that the application name is the same as the one in iTunes Connect, because it is autocompleted in the bundle identifier.

There are two ways of linking with GameKit:

  • weak link - Only link with the GameKit Framework and import GameKit/GameKit.h in your project. Useful for games who want to support earlier version of iOS (prior to 4.1) as well, disabling the optional Game Center functionality on older devices.
  • hard link - the game requires GameKit to function, so we want to ensure that only supported devices can download the game. To do this we add the gamekit key to the required device capabilities list in the Info.plist of our game

The Game Center Helper

We want to implement an easy to use, game-independent helper class for working with Game Center, a class which can be re-used in other game, having no external dependance besides GameKit. To do this, create a class GCHelper, which inherits from NSObject.

In the header file GCHelper.h, import the header files Foundation/Foundation.h and GameKit/GameKit.h or, in Xcode 5, write @import Foundation and @import GameKit at the beginning of the file.

Create two properties, a boolean named gameCenterAvailable (assign, readonly), and a private boolean with the same name, and a private boolean named userAuthenticated.

Your header file should look like this:

 

@import Foundation;

@import GameKit;

 

@interface GCHelper : NSObject {

    BOOL gameCenterAvailable;

    BOOL userAuthenticated;

}

@property (assign, readonly) BOOL gameCenterAvailable;

@end

 

Since we want this class to be a singleton, which means it can only be initialized once and that single initialization will be available everywhere, we need to move to the GCHelper.m class to implement the singleton initializer and getter method.

First, inside the @implementation, synthesize the public property added earlier by adding @synthesize gameCenterAvailable; after @implementation.

We add a static variable of type GCHelper* to contain the singleton. 

Afterwards, we create a static method for retrieving the singleton. In this method we use dispatch_once to make sure that the singleton is only ever allocated once. dispatch_once assures that the dispatched code will only be executed once, even in race conditions, therefore achieving thread safety.

 

static GCHelper *_sharedHelper = nil;

+ (GCHelper*)defaultHelper {

    // dispatch_once will ensure that the method is only called once (thread-safe)

    static dispatch_once_t pred = 0;

    dispatch_once(&pred, ^{

        _sharedHelper = [[GCHelper alloc] init];

    });

    return _sharedHelper;

}

 

To test if a certain device supports GameKit, the following function can be used:

 

- (BOOL)isGameCenterAvailable {

    // check for presence of GKLocalPlayer API

    Class gcClass = (NSClassFromString(@"GKLocalPlayer"));

   

    // check if the device is running iOS 4.1 or later

    NSString *reqSysVer = @"4.1";

    NSString *currSysVer = [[UIDevice currentDevicesystemVersion];

    BOOL osVersionSupported = ([currSysVer compare:reqSysVer

                                           options:NSNumericSearch] != NSOrderedAscending);

   

    return (gcClass && osVersionSupported); 

}

 

This should be added to the header file as well, so that it can be called externally.

 

Authentication

Register for authentication changed updates prior to executing the actual authentication, e.g. at the start of the application or while the loading screen is displayed:

 

NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];

[nc addObserver:self selector:@selector(authenticationChanged) name:GKPlayerAuthenticationDidChangeNotificationName object:nil];

 

This can be done by overloading the init method of the GCHelper: 

 

- (id)init {

    if ((self = [super init])) {

        gameCenterAvailable = [self isGameCenterAvailable];       

        if (gameCenterAvailable) {

            NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];

            [nc addObserver:self selector:@selector(authenticationChanged) name:GKPlayerAuthenticationDidChangeNotificationName object:nil];

        }

    }

    return self;

}

 

When authenticating with Game Center there are three possible outcomes of the authentication process:

  • the authentication process succeeds
  • the device does not have an authenticated player so a view controller for authentication is passed back
  • the authentication process fails and an error is passed back

We need to handle all three outcomes to be able to successfully implement Game Center. Since the actual authentication takes place asynchronously, we have to write a completion block, which will be called when the authentication finishes.

The function in GCHelper.m which performs the actual authentication can be written like this:

 

- (void)authenticateLocalUserOnViewController:(UIViewController*)viewController

                            setCallbackObject:(id)obj

                            withPauseSelector:(SEL)selector

{

    if (!gameCenterAvailable) return;

    GKLocalPlayer *localPlayer = [GKLocalPlayer localPlayer];

   

    NSLog(@"Authenticating local user...");

    if (localPlayer.authenticated == NO) {

        [localPlayer setAuthenticateHandler:^(UIViewController* authViewController, NSError *error) {

            if (authViewController != nil) {

                if (obj) {

                    [obj performSelector:selector withObject:nil afterDelay:0];

                }

               

                [viewController presentViewController:authViewController animated:YES completion:^ {

                }];

            } else if (error != nil) {

                // process error

            }

        }];

    }

    else {

        NSLog(@"Already authenticated!");

    }

} 

 

Let's talk about this code before we proceed further. To call the method, we have to pass a view controller on top of which the authentication view controller can be displayed, a callback object and a selector for it, since we want a method on the callback object to be called if the game will have to be paused to display the authentication view controller.

We first check if Game Center is available and return if it is not. If the local player is not authenticated, we start authentication with an authentication handler. This authentication handler, actually a completion block, checks if an authentication view controller was passed. If this is the case, it checks if an object was passed to the method, so that it can pause the game. After this method was called, we can safely present the authentication view controller on top of the view controller passed to the authenticateLocalUserOnViewController method. If there is an error, we should process it, for example by disabling game center functionality in our game altogether.

Do not forget to add this method to the header file.

 

The actual authentication with Game Center will take place asynchronously, that is, on another thread. The authentication is repeated when the game moves from background to foreground.

Until now, we have only handled two of the three possible outcomes. What if the authentication succeeds?

If the authentication succeeds, the selector method will be called on the GCHelper. However, we have not yet implemented it. The method should look like this: 

 

- (void)authenticationChanged {

    if ([GKLocalPlayer localPlayer].isAuthenticated && !userAuthenticated) {

        NSLog(@"Authentication changed: player authenticated.");

        userAuthenticated = TRUE;

       

        // Load the leaderboard info

        // Load the achievements       

    } else if (![GKLocalPlayer localPlayer].isAuthenticated && userAuthenticated) {

        NSLog(@"Authentication changed: player not authenticated.");

        userAuthenticated = FALSE;

    }

}

 

 

Leaderboards

General description 

Leaderboards offer a scoring system that measures how well a player does in the game. Through leaderboards players can compare their skill with other players. A game can have one or more leaderboards, which can be organized, in iOS 7, in Leaderboard Sets, offering the ability to combine several leaderboards into a single group. This can be useful to group leaderboards with different difficulty levels and/or game modes. 

 

Designing leaderboards

 

You should use multiple leaderboards, for different types of game modes or difficulty levels. To use leaderboards, you have to implement a score calculation mechanism in your game. The score of your game must be a 64-bit integer value.

The score must either be:

  • an abstract number
  • a time value (e.g. second)
  • a monetary value (e.g. Euros)

 

Creating a leaderboard

To add a new leaderboard go to iTunes Connect, go to your game and under Manage Game Center, go to Add Leaderboard. Here you have to add the leaderboard reference name, a leaderboard ID (same namespace as bundle ID) and configure the score format, as well as the localization of the leaderboard in at least one language.

 

Leaderboards exercise (Exercise 1)

The purpose of this exercise is to display the leaderboard to the user. The leaderboard is to be displayed on top of a view controller. The leaderboard identifier is already defined as kLeaderBoardIdentifier. To be able to achieve this implement the following methods in GCHelper.m:

- (void)showLeaderboardOnViewController:(UIViewController*)viewController

- (void)gameCenterViewControllerDidFinish:(GKGameCenterViewController *)gameCenterViewController

The second method is the delegate method of GKGameCenterViewController, called when the Done button is clicked. The leaderboard should be shown upon pressing “Show Leaderboard” in the main menu and closed when clicking on Done.

Download the source code here

 

Make GCHelper implement the protocol GKGameCenterControllerDelegatein its header file.

- (void)showLeaderboardOnViewController:(UIViewController*)viewController
{
    GKGameCenterViewController *gameCenterController = [[GKGameCenterViewController alloc] init];
    if (gameCenterController != nil) {
        gameCenterController.gameCenterDelegate = self;
        gameCenterController.viewState = GKGameCenterViewControllerStateLeaderboards;
        gameCenterController.leaderboardIdentifier = kLeaderBoardIdentifier;
        
        [viewController presentViewController: gameCenterController animated: YES completion:nil];
    }
}

- (void)gameCenterViewControllerDidFinish:(GKGameCenterViewController *)gameCenterViewController
{
    [gameCenterViewController dismissViewControllerAnimated:YES completion:^{
        
    }];
}

Let's discuss the solution a bit.

In the first method, a new GKGameCenterViewController is initialized. Since we need this view controller to show our leaderboards, we need to set its leaderboardIdentifier as well as its gameCenterDelegate so that upon pressing the Done button, the delegate method (gameCenterViewControllerDidFinish:) will be called. Afterwards, the newly created view controller will be displayed modally on top of the passed viewController.

In the second method, called upon pressing the Done button, the gameCenterViewController is dismissed and disappears from the screen.

Reporting a score to a leaderboard

To be able to report a score to the leaderboard, we instantiate a GKScore object with the leaderboard identifier of the leaderboard we want to post to.

GKScore has following properties:

  • value - a 64-bit integer value containing the actual score. This value can be limited by the leaderboard and reporting a wrong value will cause the score reporting to fail
  • context - a context stored in GameCenter and returned to the game. For example, if the score was done using a BMW car the context can be 1, if the context was done using a VW the context can be 2 and so on. This can be used to limit score challenges to certain game modes and configurations, so that the challenged player will have the same game environment.

To report one or more scores to the leaderboard, we use the following static method of GKScore:

+ (void)reportScores:(NSArray *)scores withCompletionHandler:(void(^)(NSError *error))completionHandler

Leaderboards exercise (Exercise 2)

The purpose of this exercise is to report the score of the game to Game Center. The leaderboard identifier is already defined as kLeaderBoardIdentifier.

In GCHelper.m, implement the method - (void)reportScore:(int64_t)score forLeaderboardID:(NSString*)identifier

In MyScene.m, report the score in the method - (void)handleGameOver before presenting the game over scene.

If the score was reported successfully it should show up on the leaderboard.

Tip: The score is already calculated by the game, in MyScene.m

 

GCHelper.m:

- (void)reportScore:(int64_t)score forLeaderboardID:(NSString*)identifier
{
    GKScore *scoreReporter = [[GKScore alloc] initWithLeaderboardIdentifier: identifier];
    scoreReporter.value = score;
    scoreReporter.context = 0;
    
    [GKScore reportScores:@[scoreReporter] withCompletionHandler:^(NSError *error) {
        if (error == nil) {
            NSLog(@"Score reported successfully!");
        } else {
            NSLog(@"Unable to report score!");
        }
    }];
}

MyScene.m:

- (void)handleGameOver {
    [gameOverSound play];
    NSDate *endTime = [[NSDate alloc] init];
    
    SKScene* gameOverScene = [[GameOverScene alloc] initWithSize:self.size score:score];
    [[GCHelper defaultHelper] reportScore:score forLeaderboardID:kLeaderBoardIdentifier];
    

In the reportScore method, we initialize a GKScore object with the leaderboard identifier passed to our method.  The GKScore object needs to have its value (of type int64_t) set; the value represents the score. The context of the score should be set as well, however in this case we set the context to 0 because we do not have a use for it. Finally we report the score, packed into an NSArray, using the static method reportScores and log the result.

 

Achievements

 

General description 

Achievements are great way to track what a player has done in the game and to give the player incentive to play further as they make progress towards completing an achievement. Each achievement has a set number of points. The game can decide when the player has made progress towards earning an achievement.

Achievements can be repetitive and/or hidden, for added surprise.

 

Designing achievements

The achievement’s goal should be well defined, for example:

  • Earn a score of over 9000
  • Kill 30 aliens
  • Last 30 seconds
  • Defeat the 1st boss

A goal statement should include a triggering condition (e.g. kill aliens) and a quantity (e.g. 30). A game can have up to 100 achievements with a total of 1000 points.

Strategies:

  • Create achievements that show the different things which can be done in the game
  • Create achievements that require skill or dedication
  • Create achievements for different sections or modes present in your game

 

Creating an achievement

In iTunes Connect, go to your app and under Manage Game Center, go to Add Achievement. Add the achievement reference name, an achievement ID (same namespace as bundle ID), set the points and options, as well as the localization and the achievement picture (required).

 

Reporting progress on an achievement

To be able to report progress on an achievement, we can either instantiate a GKAchievement object or retrieve all achievements from Game Center. Check if achievement is not 100% completed and if not, set the new progress and report it to Game Center using the static method of GKAchievement presented below.

+ (void)reportAchievements:(NSArray *)achievements withCompletionHandler:(void(^)(NSError *error))completionHandler

To receive notifications on achievement completion set the property showsCompletionBanner to YES.

To reset all the achievements, call the static method + (void)resetAchievementsWithCompletionHandler:(void(^)(NSError *error))completionHandler

Loading achievements

To load achievements, we first need a container for them. For this purpose, create a property like the one shown below in GCHelper.m.

@property (nonatomic, strong) NSMutableDictionary *achievementsDictionary;

Afterwards, we create two functions, one for loading the achievements and one a getter-function for retrieving achievements.

- (void)loadAchievements

{

    self.achievementsDictionary = [[NSMutableDictionaryalloc] init];

    [GKAchievementloadAchievementsWithCompletionHandler:^(NSArray *achievements, NSError *error) {

        if (error != nil)

        {

            // Handle the error.

            NSLog(@"Error while loading achievements: %@", error.description);

        }

        elseif (achievements != nil)

        {

            // Process the array of achievements.

            for (GKAchievement* achievement in achievements)

                self.achievementsDictionary[achievement.identifier] = achievement;

        }

    }];

}

The loadAchievements method, which is to be called upon successful authentication in authenticationChanged, initializes the achievements dictionary and then proceeds with loading the achievements using the static method loadAchievementsWithCompletionHandler of GKAchievement. Upon completion of the authentication, we need to add the achievements passed to us into the dictionary, so that we can access them using their identifier. If the method fails, an error is logged to the console.

- (GKAchievement*)getAchievementForIdentifier: (NSString*) identifier

{

    GKAchievement *achievement = [self.achievementsDictionaryobjectForKey:identifier];

    if (achievement == nil)

    {

        achievement = [[GKAchievementalloc] initWithIdentifier:identifier];

        self.achievementsDictionary[achievement.identifier] = achievement;

    }

    return achievement;

}

The getAchievementForIdentifier method, which is the getter-method for achievements and returns a GKAchievement for a specific identifier from the dictionary. If such an object is not found, an achievement with the passed identifier is initialized, added to the dictionary and then returned by the method.

 

Achievements exercise (Exercise 3) 

Implement the achievement progress reporting in GCHelper.m: 

 

- (void)reportAchievementIdentifier: (NSString*) identifier percentComplete: (float) percent

Implement the achievement progress resetting:

- (void)resetAchievements

 

The achievements can be retrieved using - (GKAchievement*)getAchievementForIdentifier: (NSString*) identifier

When the exercise is completed correctly, an achievement will be reported automatically upon starting to play the game.

 

 
- (void)reportAchievementIdentifier: (NSString*) identifier percentComplete: (float) percent
{
    GKAchievement *achievement = [self getAchievementForIdentifier:identifier];
    if (achievement && achievement.percentComplete != 100.0) {
        achievement.percentComplete = percent;
        achievement.showsCompletionBanner = YES;
        
        [GKAchievement reportAchievements:@[achievement] withCompletionHandler:^(NSError *error) {
            if (error != nil) {
                NSLog(@"Error while reporting achievement: %@", error.description);
            }
        }];
    }
}

- (void)resetAchievements
{
    // Clear all locally saved achievement objects.
    self.achievementsDictionary = [[NSMutableDictionary alloc] init];
    // Clear all progress saved on Game Center.
    [GKAchievement resetAchievementsWithCompletionHandler:^(NSError *error)
     {
         if (error != nil) {
             // handle the error.
             NSLog(@"Error while reseting achievements: %@", error.description);

         }
     }];
}

To report an achievement, we first use the getter-method for retrieving achievements with an identifier. We check if an achievement was actually returned and if it was not 100% completed and, if this is not the case, we set the new completion percentage and activate the displaying of the completion banner, which notifies the user of completing an achievement by showing an on-screen notification. Finally, we report the GKAchievement wrapped in an NSArray and log the result.

To reset the achievements, we remove all objects from the dictionary and call the static method resetAchievementsWithCompletionHandler of GKAchievement to reset our achievement progress on the Game Center servers.

Achievements exercise (Exercise 4)

 

In MyScene.m in the handleGameOver method, do the following changes:

  • Modify the game to report an achievement on achieving a certain score. 
  • Modify the game to report an achievement on surviving for a certain amount of time.

Possible achievements are:

  • Score more than 500 (identifier - kAchievement500Score)
  • Score more than 1000 (identifier - kAchievement1000Score)
  • Survive 30 seconds or more (identifier - kAchievement30Sec)
  • Survive 60 seconds or more (identifier - kAchievement1Min)

Hint: Use an NSDate object to compare the time interval between the startDate object, already defined, and the current time on game over

MyScene.m:

- (void)handleGameOver {
    [gameOverSound play];
    NSDate *endTime = [[NSDate alloc] init];
    
    SKScene* gameOverScene = [[GameOverScene alloc] initWithSize:self.size score:score];
    [[GCHelper defaultHelper] reportScore:score forLeaderboardID:kLeaderBoardIdentifier];
    
    // check if the score is enough to earn an achievement
    if (score > 500) {
        [[GCHelper defaultHelper] reportAchievementIdentifier:kAchievement500Score percentComplete:100.0];
        // check if the score is enough to earn another achievement
        if (score > 1000) {
            [[GCHelper defaultHelper] reportAchievementIdentifier:kAchievement1000Score percentComplete:100.0];
        }
    }

    // check if the time interval in seconds is greater than 30s
    if ([endTime timeIntervalSinceDate:startTime] > 30.0) {
        [[GCHelper defaultHelper] reportAchievementIdentifier:kAchievement30Sec percentComplete:100.0];
        // check if the time interval in seconds is greater than 1 min
        if ([endTime timeIntervalSinceDate:startTime] > 60.0) {
            [[GCHelper defaultHelper] reportAchievementIdentifier:kAchievement1Min percentComplete:100.0];

        }
    }
    ((AppDelegate*)[[UIApplication sharedApplication] delegate]).gameScene = nil;
    [self.view presentScene: gameOverScene];

}

First, retrieve the end time of the game using an NSDate variable. Report the 500 score achievement if the score is greater than 500, report both of them if greater than 1000. Report the 30s survival achievement if the time difference is greater than 30s, report both of them if greater than 1 minute.

 

Challenges

General description

 

Challenges are a way for players to test their progress against each other. We all know it is more satisfying to beat a friend at a game, so we want to provide the players with a way of doing just that. Through challenges players compete indirectly, with each other.

There are two kinds of challenges:

  • Score challenge
  • Achievement challenge

Challenges can be issued from Game Center or app and require no additional support, however their functionality can be extended. A push notification is shown upon receiving a challenge from a friend. When this notification is clicked, the game should begin automatically - however we have to implement this in our game.

 

Issuing a challenge

From Game Center or your game, go to Games, click on a game and a score or achievement in that game. Afterwards, you can click the Challenge Friends button to be able to send a challenge to one or more friends. Finally, you can write a message to that/those friend(s) and send the challenge. The friend(s) will receive a push notification on his device showing him/her that you have sent a challenge.

Challenge exercise (Exercise 5)

 

Implement the event handler for challenge events, using logs and starting the gameplay where necessary. Write the GKLocalPlayerListener delegate methods in MainScreenViewController presented below. The segue identifier for starting a new game is startPlaying.

// issued when the player completed a challenge sent by a friend

- (void)player:(GKPlayer *)player didCompleteChallenge:(GKChallenge *)challenge issuedByFriend:(GKPlayer *)friendPlayer

// issued when a friend of the player completed a challenge sent by the player

- (void)player:(GKPlayer *)player issuedChallengeWasCompleted:(GKChallenge *)challenge byFriend:(GKPlayer *)friendPlayer

// issued when a player wants to play the challenge and has just started the game (from a notification)

- (void)player:(GKPlayer *)player wantsToPlayChallenge:(GKChallenge *)challenge

// issued when a player wants to play the challenge and is in the game (the game was running while the challenge was sent)

- (void)player:(GKPlayer *)player didReceiveChallenge:(GKChallenge *)challenge

 

Solution 

- (void)player:(GKPlayer *)player didCompleteChallenge:(GKChallenge *)challenge issuedByFriend:(GKPlayer *)friendPlayer

{

    NSLog(@"Challenge %@ sent by %@ completed", challenge.description , friendPlayer.displayName);

 

Log the player’s completed challenge.

 

- (void)player:(GKPlayer *)player issuedChallengeWasCompleted:(GKChallenge *)challenge byFriend:(GKPlayer *)friendPlayer

{

    NSLog(@"Your friend %@ has successfully completed the %@ challenge", friendPlayer.displayName, challenge.description);

}

Log the friends’ completed challenge.

 

- (void)player:(GKPlayer *)player wantsToPlayChallenge:(GKChallenge *)challenge

{

    [self performSegueWithIdentifier:@"startPlaying" sender:self];

} 

Start a new game. 

 

- (void)player:(GKPlayer *)player didReceiveChallenge:(GKChallenge *)challenge

{

    NSString *friendMsg = [[NSString alloc] initWithFormat:@"Your friend %@ has invited you to a challenge: %@", player.displayName, challenge.message];

    UIAlertView *theChallenge = [[UIAlertView alloc] initWithTitle:@"Want to take the challenge?" message:friendMsg delegate:self cancelButtonTitle:@"Challenge accepted" otherButtonTitles:@"No", nil];

    [theChallenge show];

}

- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex

{

    if (buttonIndex == 0)  [selfperformSegueWithIdentifier:@"startPlaying"sender:self];

}

Present a new UIAlertView in which the player can choose to take the challenge now. Obviously, GCHelper needs to implement UIAlertViewDelegate.

 

The Game Center Helper

We have implemented an easy to use, game-independent helper class for working with Game Center, in GCHelper.m and GCHelper.h. This helper class can be re-used in your games and provides the necessary functionalities for authentication, viewing and reporting scores, viewing and reporting achievements and integrating challenges.

Download the final source code here

Summary

In this tutorial you have learned:

  • how to develop a Game Center integrated game
  • how to create a leaderboard and report scores to it
  • how to create & design achievements
  • how to issue challenges to other players and respond to them gracefully

The Game Center offers multiple possibilities for improving the addiction factor of a game, which helps the developer(s) make more revenue in turn.

 

Outlook 

To find out more about Leaderboard Sets: 

https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/GameKit_Guide/LeaderBoards/LeaderBoards.html#//apple_ref/doc/uid/TP40008304-CH6-SW44

 

Further topics not discussed in this tutorial (Turn-based games, Multiplayer Games) are discussed in the Multiplayer Games tutorial:

http://www1.in.tum.de/lehrstuhl_1/people/98-teaching/tutorials/508-sgd-ws13-tutorial-multiplayer-games

 

For an iOS 6 Game Center Tutorial

http://mobile.tutsplus.com/tutorials/iphone/ios-sdk-game-center-achievements-and-leaderboards-part-1/

http://mobile.tutsplus.com/tutorials/iphone/ios-sdk-game-center-achievements-and-leaderboards-part-2/

 

To learn further about working with GameKit and doing more custom UIs, check out the GameKit Programming Guide (Documentation not final as of 29.09.2013)

https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/GameKit_Guide/Introduction/Introduction.html#//apple_ref/doc/uid/TP40008304-CH1-SW1

 

References

https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/GameKit_Guide/Introduction/Introduction.html#//apple_ref/doc/uid/TP40008304-CH1-SW1

https://developer.apple.com/wwdc/videos/?id=504

http://devstreaming.apple.com/videos/wwdc/2013/504xbx3x55lc470bv6s8dk2lcg28/504/504.pdf?dl=1

http://mobile.tutsplus.com/tutorials/iphone/ios-sdk-game-center-achievements-and-leaderboards-part-1/

http://www.tech-wanderings.com/ios-game-center-achievement-display