1

I have successfully added Game Center capabilities to my app. When the app is opened it successfully authenticates the user and shows the "Welcome back (UserName)" banner.

However, I am not sure of how to add a leaderboard to the game. I was wondering if someone could help me A: Help me understand how to link the leaderboard i made in iTunes connect with the app and make highscore the value of the leaderboard. And B: Make the leaderboard show up in the app with all the rankings.

All the code for gamecenter in my app so far is below.

Interface File:

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


@interface GCHelper : NSObject {

BOOL gameCenterAvailable;
BOOL userAuthenticated;
}

@property (assign, readonly) BOOL gameCenterAvailable;

+ (GCHelper *)sharedInstance;
-(void)authenticateLocalUser;

@end

Implementation File:

#import "GCHelper.h"



@implementation GCHelper
@synthesize  gameCenterAvailable;

#pragma mark initialization

static GCHelper *sharedHelper = nil;
+ (GCHelper *) sharedInstance {
if (!sharedHelper) {
    sharedHelper = [[GCHelper alloc] init];
}
return sharedHelper;

}

- (BOOL)isGameCenterAvailable {
Class gcClass = (NSClassFromString(@"GKLocalPlayer"));

NSString *reqSysVer = @"4.1";
NSString *currSysVer = [[UIDevice currentDevice] systemVersion];
BOOL osVersionSupported = ([currSysVer compare:reqSysVer
                                       options:NSNumericSearch] != NSOrderedAscending);
return (gcClass && osVersionSupported);
}

- (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;
}

-(void)authenticationChanged {

if ([GKLocalPlayer localPlayer].isAuthenticated && !userAuthenticated) {
    NSLog(@"Authentication changed: player authenticated.");
    userAuthenticated = TRUE;
} else if (![GKLocalPlayer localPlayer].isAuthenticated && userAuthenticated) {
    NSLog(@"Authentication changed: player not authenticated");
    userAuthenticated = FALSE;
}
}

#pragma mark User Functions

-(void) authenticateLocalUser {

if(!gameCenterAvailable) return;

NSLog(@"Authentication local user...");
if ([GKLocalPlayer localPlayer].authenticated == NO) {
    [[GKLocalPlayer localPlayer] authenticateWithCompletionHandler:nil];
} else {
    NSLog(@"Already authenticated!");
}
}

@end

OKAY, so. The code is working now but when the code to access the leaderboard returns an error, I have no code to handle it and instead just makes the app go into a frozen state and makes it unable to function.

Code being called to access leaderboard :

- (void) presentLeaderboards
{
GKGameCenterViewController* gameCenterController = [[GKGameCenterViewController alloc]      init];
gameCenterController.viewState = GKGameCenterViewControllerStateLeaderboards;
gameCenterController.gameCenterDelegate = self;
[self presentViewController:gameCenterController animated:YES completion:nil];

}
  • Did you use the Ray Wenderlich tutorial on Game Center? Your code looks familiar! – Wyetro Jul 27 '14 at 05:13
  • It was a YouTube tutorial that ended before it told me how to add a leaderboard I'm not sure of the uploader – user3752308 Jul 27 '14 at 05:14
  • Check out my answer, it is pretty straight forward and works. I have two games on the app store and have submitted a third and they all use this. This will also work for multiple leaderboards in a single game! – Wyetro Jul 27 '14 at 05:15
  • Have a look at this detailed tutorial about Game Center from [Raywenderlich website](http://www.raywenderlich.com/60980/game-center-tutorial-how-to-make-a-simple-multiplayer-game-with-sprite-kit-part-1). This tutorial will give you idea about what you want to achieve – iOSAppDev Jul 27 '14 at 05:59
  • My instructions are a simplified version of the Ray Wenderlich tutorial. – Wyetro Jul 27 '14 at 15:18
  • I have added my last issue onto the question down the bottom – user3752308 Jul 29 '14 at 09:15

1 Answers1

1

To set up a leaderboard go to iTunes Connect > Manage Your Apps > Your App > Manage Game Center > Add Leaderboard > Single Leaderboard.

Give your leaderboard a name and all of the required organizational information needed.

Add this method to your GCHelper.m:

-(void) submitScore:(int64_t)score Leaderboard: (NSString*)leaderboard
{

    //1: Check if Game Center
    //   features are enabled
    if (!_gameCenterFeaturesEnabled) {
        return;
    }

    //2: Create a GKScore object
    GKScore* gkScore =
    [[GKScore alloc]
     initWithLeaderboardIdentifier:leaderboard];

    //3: Set the score value
    gkScore.value = score;

    //4: Send the score to Game Center
    [gkScore reportScoreWithCompletionHandler:
     ^(NSError* error) {

         [self setLastError:error];

         BOOL success = (error == nil);

         if ([_delegate
              respondsToSelector:
              @selector(onScoresSubmitted:)]) {

             [_delegate onScoresSubmitted:success];
         }
     }];


}

And add this to your GCHelper.h:

-(void) submitScore:(int64_t)score Leaderboard: (NSString*)leaderboard;

Now in the .m for your game add this method to whatever method you call when the game is over:

[[GCHelper sharedGameKitHelper] submitScore:highScore Leaderboard:LeaderboardName];

In this example highScore is the int_64 value of your score and LeaderboardName is an NSString equal to the Leaderboard Identifier you set up in iTunes Connect. Also be sure to add Game Center capabilities to your application.

After that you should be able to submit high scores!

ALSO ADD THIS TO GCHelper.m

-(void) setLastError:(NSError*)error {
    _lastError = [error copy];
    if (_lastError) {
        NSLog(@"GameKitHelper ERROR: %@", [[_lastError userInfo]
                                           description]);
    }
}

AND ALSO ADD THIS TO GCHelper.h

@property (nonatomic, assign)id<GCHelperProtocol> delegate;

Here is my GCHelper.h:

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

//   Include the GameKit framework
#import <GameKit/GameKit.h>

//   Protocol to notify external
//   objects when Game Center events occur or
//   when Game Center async tasks are completed
@protocol GCHelperProtocol<NSObject>


-(void) onScoresSubmitted:(bool)success;


@end


@interface GCHelper : NSObject

@property (nonatomic, assign)id<GCHelperProtocol> delegate;

// This property holds the last known error
// that occured while using the Game Center API's
@property (nonatomic, readonly) NSError* lastError;

+ (id) sharedGameKitHelper;

// Player authentication, info
-(void) authenticateLocalPlayer;

//Scores
-(void) submitScore:(int64_t)score Leaderboard: (NSString*)leaderboard;




@end

And here my GCHelper.m:

#import "GCHelper.h"

@interface GCHelper ()
<GKGameCenterControllerDelegate> {
    BOOL _gameCenterFeaturesEnabled;
}
@end

@implementation GCHelper

#pragma mark Singleton stuff

+(id) sharedGameKitHelper {
    static GCHelper *sharedGameKitHelper;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedGameKitHelper =
        [[GCHelper alloc] init];
    });
    return sharedGameKitHelper;
}

#pragma mark Player Authentication

-(void) authenticateLocalPlayer {

    GKLocalPlayer* localPlayer =
    [GKLocalPlayer localPlayer];

    localPlayer.authenticateHandler =
    ^(UIViewController *viewController,
      NSError *error) {

        [self setLastError:error];


        if (localPlayer.authenticated) {
            _gameCenterFeaturesEnabled = YES;
        } else if(viewController) {
            [self presentViewController:viewController];
        } else {
            _gameCenterFeaturesEnabled = NO;
        }
    };
}

#pragma mark Property setters

-(void) setLastError:(NSError*)error {
    _lastError = [error copy];
    if (_lastError) {
        NSLog(@"GameKitHelper ERROR: %@", [[_lastError userInfo]
                                           description]);
    }
}

#pragma mark UIViewController stuff

-(UIViewController*) getRootViewController {
    return [UIApplication
            sharedApplication].keyWindow.rootViewController;
}

-(void)presentViewController:(UIViewController*)vc {
    UIViewController* rootVC = [self getRootViewController];
    [rootVC presentViewController:vc animated:YES
                       completion:nil];
}


#pragma mark Scores

- (void) reportAchievementWithID:(NSString*) AchievementID {

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

        if(error) NSLog(@"error reporting ach");

        for (GKAchievement *ach in achievements) {
            if([ach.identifier isEqualToString:AchievementID]) { //already submitted
                return ;
            }
        }

        GKAchievement *achievementToSend = [[GKAchievement alloc] initWithIdentifier:AchievementID];
        achievementToSend.percentComplete = 100;
        achievementToSend.showsCompletionBanner = YES;
        [achievementToSend reportAchievementWithCompletionHandler:NULL];

    }];

}

-(void) submitScore:(int64_t)score Leaderboard: (NSString*)leaderboard
{

    //1: Check if Game Center
    //   features are enabled
    if (!_gameCenterFeaturesEnabled) {
        return;
    }

    //2: Create a GKScore object
    GKScore* gkScore =
    [[GKScore alloc]
     initWithLeaderboardIdentifier:leaderboard];

    //3: Set the score value
    gkScore.value = score;

    //4: Send the score to Game Center
    [gkScore reportScoreWithCompletionHandler:
     ^(NSError* error) {

         [self setLastError:error];

         BOOL success = (error == nil);

         if ([_delegate
              respondsToSelector:
              @selector(onScoresSubmitted:)]) {

             [_delegate onScoresSubmitted:success];
         }
     }];


}




-(void) gameCenterViewControllerDidFinish:(GKGameCenterViewController *)gameCenterViewController
{
    //nothing
}

@end
Wyetro
  • 8,439
  • 9
  • 46
  • 64
  • This is a link to a screen shot of my project and the errors i am getting using this code. http://aphprojects.files.wordpress.com/2014/07/screen-shot-2014-07-28-at-11-35-44-am.png – user3752308 Jul 28 '14 at 01:39
  • Added that extra code you posted and have these new errors. https://fbcdn-sphotos-h-a.akamaihd.net/hphotos-ak-xpf1/v/t35.0-12/10587088_748152948574512_1025435203_o.jpg?oh=7029983e53c9a3e875b79853585e4941&oe=53D7BE78&__gda__=1406647272_2ccc848c1c28c4339e981d9e1b16ae29 – user3752308 Jul 28 '14 at 07:28
  • Ok just look at the bottom of my answer, I copy and pasted my GCHelper.h and GCHelper.m. That should solve everything. – Wyetro Jul 28 '14 at 12:48
  • Okay, no errors anymore which is great! Haven't been able to test it yet but I will this afternoon and tell you how it goes. Also, with the code you call at the end of the game to submit highscore should it be done with the leadboard id with an @ and " marks, like @"LeaderboardID"; – user3752308 Jul 28 '14 at 21:35
  • For the leaderboard write the name of it in itunes connect. – Wyetro Jul 28 '14 at 21:37
  • Yeah, but do I write it in the form of @"LeadboardID" or LeaderboardID – user3752308 Jul 28 '14 at 22:56
  • You want it to equal an NSString that is the same as your leaderboard id. So the @"LeaderboardID". – Wyetro Jul 28 '14 at 22:58
  • Sweet, thanks. Also, What is the command to open the leaderboard to check out the ranks. – user3752308 Jul 28 '14 at 23:08
  • I've answered that somewhere else, just check it out on the other thread. Glad I could help you. Please mark it as the accepted answer, and upvote. – Wyetro Jul 28 '14 at 23:10
  • Please up vote the answer on the other question for opening the leaderboards. – Wyetro Jul 29 '14 at 03:05
  • Hey Wyatt, It is logging in and bringing the game centre up when I press the button but after pressing the button my app stops functioning and just freezes... Also I am unable to tap the "Done" button to close the leaderboard – user3752308 Jul 29 '14 at 09:07
  • Make sure you have the GameCenterViewControllerDidFinish method at the end of my answer, that will allow you to use the done button. And make sure in your AppDelegate.m you have [[GCHelper sharedGameKitHelper] authenticateLocalPlayer]; – Wyetro Jul 29 '14 at 12:48
  • Thanks for the response I will try it out in the morning – user3752308 Jul 29 '14 at 12:59
  • I have found the following error which seems to explain it. Method 'gameCenterViewControllerDidFinish:' in protocol not implemented. I have the exact same code you have and i am importing the "GCHelper.h" into my file where I call "presentLeaderboard" – user3752308 Jul 29 '14 at 21:33
  • GameCenterViewControllerDidFinish is the last method I put in the code. Just copy and paste it in and it should work. – Wyetro Jul 29 '14 at 21:35