Search Unity

  1. Unity 6 Preview is now available. To find out what's new, have a look at our Unity 6 Preview blog post.
    Dismiss Notice
  2. Unity is excited to announce that we will be collaborating with TheXPlace for a summer game jam from June 13 - June 19. Learn more.
    Dismiss Notice
  3. Dismiss Notice

Unity3d GameCenter Leaderboard Tutorial

Discussion in 'iOS and tvOS' started by fawzma, Sep 17, 2011.

  1. fawzma

    fawzma

    Joined:
    Sep 17, 2011
    Posts:
    1
    Hi, after pulling my hair out for a few days, I finally figured it out. These instructions will also work for the Storekit as well. For the StoreKit, you would just use storekit delegates like the leaderboard delegate.

    Get the example native code sample from the resources here and do the following. This isn't the most elegant code, but it does the job. One thing I did notice is, the leaderboard will not work when debugging. But works just fine when launched on its own.

    Add the GameKit framework.

    The next part is the key to adding subviews.

    In AppController.mm

    Code (csharp):
    1.  
    2. controller.view = view;
    3. //[_window addSubview:view];
    4. //CUSTOM VIEW CONTROLLER UIViewController
    5. UIViewController *vc = [[UIViewController alloc] init];
    6. [vc.view addSubview:view];
    7. [vc.view setTag:999];
    8. [_window addSubview:vc.view];
    9.  
    Next I made a class to deal with game center functions, in this case I'm only working with the leaderboard.

    gameCenter.h

    Code (csharp):
    1. #import <Foundation/Foundation.h>
    2. #import <GameKit/GameKit.h>
    3.  
    4.  
    5. @interface gameCenter : NSObject <GKLeaderboardViewControllerDelegate>{
    6. @private
    7.    
    8. }
    9.  
    10. - (void) reportScore: (int64_t) score forCategory: (NSString*) category;
    11. - (void)postScore:(int64_t)score forCategory:(NSString *)category;
    12. - (void) authenticateLocalPlayer;
    13. - (BOOL)isGameCenterAvailable;
    14. - (void)leaderboardViewControllerDidFinish:(GKLeaderboardViewController *)vc;
    15. - (void) retrieveScoresForPlayers:(NSArray *)players category:(NSString *)category range:(NSRange)range playerscope:(GKLeaderboardPlayerScope)playerscope timescope:(GKLeaderboardTimeScope)timescope;
    16. - (void) leaderboardSelected: (id)sender : (UIViewController*)v;
    17.  
    18.  
    19. @end
    gameCenter.mm

    Code (csharp):
    1. #import "gameCenter.h"
    2.  
    3.  
    4. @implementation gameCenter
    5.  
    6. - (id)init
    7. {
    8.     self = [super init];
    9.     if (self) {
    10.         // Initialization code here.
    11.     }
    12.    
    13.     return self;
    14. }
    15.  
    16. - (void)dealloc
    17. {
    18.     [super dealloc];
    19. }
    20.  
    21. - (void) reportScore: (int64_t) score forCategory: (NSString*) category
    22.  
    23. {
    24.    
    25.    
    26.     GKScore *scoreReporter = [[[GKScore alloc] initWithCategory:category] autorelease];
    27.    
    28.     scoreReporter.value = score;
    29.    
    30.     [scoreReporter reportScoreWithCompletionHandler: ^(NSError *error)
    31.      
    32.      {
    33.          if (error != nil)
    34.          {
    35.              // handle the reporting error
    36.              //NSLog([error description]);
    37.              
    38.          }
    39.          
    40.          //[self callDelegateOnMainThread: @selector(scoreReported:) withArg: NULL error: error];
    41.          
    42.      }];
    43.    
    44. }
    45.  
    46. - (void)postScore:(int64_t)score forCategory:(NSString *)category
    47. {
    48.    
    49.     GKLeaderboard *query = [[GKLeaderboard alloc]init];
    50.     query.category = category;
    51.    
    52.     if (query != nil)
    53.        
    54.     {
    55.        
    56.         [query loadScoresWithCompletionHandler: ^(NSArray *scores, NSError *error) {
    57.            
    58.             if (error != nil){
    59.                
    60.                 // Handle the error.
    61.                 //NSLog([error description]);
    62.                
    63.             }
    64.             if (scores != nil){
    65.                
    66.                 // Process the score.
    67.                
    68.                 int64_t newScore = query.localPlayerScore.value + score;
    69.                
    70.                 [self reportScore:newScore forCategory:category];
    71.                
    72.                
    73.             }
    74.            
    75.            
    76.            
    77.         }];
    78.        
    79.        
    80.     }
    81. }
    82.  
    83. - (void) authenticateLocalPlayer
    84. {
    85.    
    86.     if([self isGameCenterAvailable])
    87.     {
    88.         GKLocalPlayer *localPlayer = [GKLocalPlayer localPlayer];
    89.         [localPlayer authenticateWithCompletionHandler:^(NSError *error)
    90.          {
    91.              
    92.              if (localPlayer.isAuthenticated){
    93.                  // Perform additional tasks for the authenticated player.
    94.                  NSLog(@"PLAYER AUTHENICATED");
    95.              }else{
    96.                  NSLog(@"PLAYER NOT AUTHENICATED");
    97.              }
    98.              
    99.              
    100.              
    101.          }];
    102.        
    103.        
    104.     }
    105. }
    106.  
    107.  
    108. - (BOOL)isGameCenterAvailable
    109. {
    110.     // Check for presence of GKLocalPlayer class.
    111.     BOOL localPlayerClassAvailable = (NSClassFromString(@"GKLocalPlayer")) != nil;
    112.    
    113.     // The device must be running iOS 4.1 or later.
    114.     NSString *reqSysVer = @"4.1";
    115.     NSString *currSysVer = [[UIDevice currentDevice] systemVersion];
    116.     BOOL osVersionSupported = ([currSysVer compare:reqSysVer options:NSNumericSearch] != NSOrderedAscending);
    117.     return (localPlayerClassAvailable  osVersionSupported);
    118. }
    119.  
    120. - (void)leaderboardViewControllerDidFinish:(GKLeaderboardViewController *)vc
    121. {
    122.     [vc dismissModalViewControllerAnimated:YES];
    123.     [vc.view.superview removeFromSuperview];
    124.     [vc release];
    125. }
    126.  
    127.  
    128.  
    129. //- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
    130. //return (interfaceOrientation == UIInterfaceOrientationPortrait);
    131. //}
    132. - (void) retrieveScoresForPlayers:(NSArray *)players category:(NSString *)category range:(NSRange)range playerscope:(GKLeaderboardPlayerScope)playerscope timescope:(GKLeaderboardTimeScope)timescope
    133. {
    134.     GKLeaderboard* leaderboard = nil;
    135.     if ([players count] > 0)
    136.     {
    137.         leaderboard = [[[GKLeaderboard alloc] initWithPlayerIDs:players] autorelease];
    138.     }
    139.     else
    140.     {
    141.         leaderboard = [[[GKLeaderboard alloc] init] autorelease];
    142.         leaderboard.playerScope = playerscope;
    143.     }
    144.    
    145.     NSLog(@"retrieve scores");
    146.    
    147.     if (leaderboard !=nil)
    148.     {
    149.         leaderboard.timeScope = timescope;
    150.         leaderboard.category = category;
    151.         leaderboard.range = range;
    152.        
    153.         NSLog(@"leaderboard");
    154.        
    155.         [leaderboard loadScoresWithCompletionHandler:^(NSArray* scores, NSError* error)
    156.          {
    157.              //lasterror = error;
    158.              if (error == nil)
    159.                  NSLog(@"leaderboard present!");
    160.              //[self showLeaderboard];
    161.              
    162.          }];
    163.     }
    164.    
    165. }
    166.  
    167.  
    168.  
    169. - (void) leaderboardSelected: (id)sender : (UIViewController*)v
    170. {
    171.     CGSize screenSize = [[UIScreen mainScreen] bounds].size;
    172.     UIWindow* window = [UIApplication sharedApplication].keyWindow;
    173.     GKLeaderboardViewController *leaderboardController = [[GKLeaderboardViewController alloc] init];  
    174.     if (leaderboardController != nil) {
    175.         leaderboardController.leaderboardDelegate = self;
    176.        
    177.         UIViewController *glView2 = [[UIViewController alloc] init];
    178.         [window addSubview: glView2.view];
    179.         [glView2 presentModalViewController: leaderboardController animated: YES];
    180.        
    181.         leaderboardController.view.transform = CGAffineTransformMakeRotation(0.0f);
    182.         [leaderboardController.view setCenter:CGPointMake(screenSize.width/2, screenSize.height/2)];
    183.         leaderboardController.view.bounds = CGRectMake(0, 0, screenSize.width, screenSize.height);
    184.     }
    185.  
    186.  
    187. }
    188.  
    189. @end
    190.  
    BonjourClientImpl.h

    Code (csharp):
    1.  
    2. #import <Foundation/Foundation.h>
    3. #import <GameKit/GameKit.h>
    4. #import "gameCenter.h"
    5. //#import "RootViewController.h"
    6.  
    7. @interface NetServiceBrowserDelegate : NSObject <GKLeaderboardViewControllerDelegate>
    8. {
    9.     // Keeps track of available services
    10.     NSMutableArray *services;
    11.    
    12.     // Keeps track of search status
    13.     NSString* status;
    14.     BOOL searching;
    15.     gameCenter *gamecenter;
    16.    
    17. }
    18.  
    19.  
    20.  
    21. // NSNetServiceBrowser delegate methods for service browsing
    22. + (void)auth;
    23. - (id)init;
    24. - (void)dealloc;
    25.  
    26. @end
    27.  

    BonjourClientImpl.mm

    Code (csharp):
    1.  
    2. #import "BonjourClientImpl.h"
    3. #import "AppController.h"
    4.  
    5.  
    6.  
    7. @implementation NetServiceBrowserDelegate
    8.  
    9.  
    10.  
    11. - (id)init
    12. {
    13.     self = [super init];
    14.     services = [[NSMutableArray alloc] init];
    15.     searching = NO;
    16.     status = @"Initializing";
    17.    
    18.     gamecenter = [[gameCenter alloc] init];
    19.    
    20.     return self;
    21. }
    22.  
    23.  
    24.  
    25. - (void)dealloc
    26. {
    27.     [services release];
    28.    
    29.     [super dealloc];   
    30. }
    31.  
    32. + (void)auth
    33. {
    34.  
    35. }
    36.  
    37.  
    38.  
    39. @end
    40.  
    41. //static NetServiceBrowserDelegate* delegateObject = nil;
    42. //static NSNetServiceBrowser *serviceBrowser = nil;
    43. gameCenter *gamecenter = [[gameCenter alloc] init];
    44.  
    45. void authenticate(){
    46.     NSLog(@"AUTHING");
    47.     [gamecenter authenticateLocalPlayer];
    48.     [gamecenter leaderboardSelected:nil :nil];
    49. }
    50.  
    51. void deallocGC(){
    52.     [gamecenter release];
    53.     gamecenter = nil;
    54. }
    55.  
    56. // Converts C style string to NSString
    57. NSString* CreateNSString (const char* string)
    58. {
    59.     if (string)
    60.         return [NSString stringWithUTF8String: string];
    61.     else
    62.         return [NSString stringWithUTF8String: ""];
    63. }
    64.  
    65. // Helper method to create C string copy
    66. char* MakeStringCopy (const char* string)
    67. {
    68.     if (string == NULL)
    69.         return NULL;
    70.    
    71.     char* res = (char*)malloc(strlen(string) + 1);
    72.     strcpy(res, string);
    73.     return res;
    74. }
    75.  
    76. // When native code plugin is implemented in .mm / .cpp file, then functions
    77. // should be surrounded with extern "C" block to conform C function naming rules
    78. extern "C" {
    79.  
    80.     void _output ()
    81.     {
    82.         //NSLog(@"%d DEBUGGED STRING",[NetServiceBrowserDelegate getCount]);
    83.          
    84.     }
    85.    
    86.     void _authplayer()
    87.     {
    88.         [NetServiceBrowserDelegate auth];
    89.         NSLog(@"AUTH PLAYER");
    90.     }
    91.    
    92.     void _leaderboard()
    93.     {
    94.         authenticate();
    95.         //[NetServiceBrowserDelegate auth];
    96.         //[NetServiceBrowserDelegate leaderboardSelected:nil];
    97.         NSLog(@"LEADER BOARD");
    98.     }
    99.  
    100.    
    101. }
    102.  
    103.  
    Add this script to your Unity project, and attach to your main camera

    SomeScript.cs

    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using System.Runtime.InteropServices;
    4.  
    5. class SomeScript : MonoBehaviour {
    6.    // This tells unity to look up the function FooPluginFunction
    7.    // inside the static binary
    8.    Rect windowRect = new Rect(20, 20, 120, 50);
    9.    
    10.    [DllImport ("__Internal")]
    11.    private static extern void _output ();
    12.    
    13.    [DllImport ("__Internal")]
    14.    private static extern void _authplayer ();
    15.    
    16.    [DllImport ("__Internal")]
    17.    private static extern void _leaderboard ();
    18.  
    19.    void Awake () {
    20.       //// Calls the native FooPluginFunction
    21.       //// And prints 5 to the console
    22.       //print (getOutput ());
    23.    }
    24.    
    25.  
    26.  
    27.     void OnGUI()
    28.     {
    29.         // Register the window. Notice the 3rd parameter
    30.         windowRect = GUI.Window(0, windowRect, DoMyWindow, "My Window");
    31.     }
    32.  
    33.     // Make the contents of the window
    34.     void DoMyWindow(int windowID)
    35.     {
    36.         if(GUI.Button(new Rect(10,20,100,20), "Hello World")){
    37.             Debug.Log("Got a click");
    38.             getOutput ();
    39.         }
    40.     }
    41.    
    42.     // Stops lookup current lookup
    43.     public static void getOutput()
    44.     {
    45.         // Call plugin only when running on real device
    46.         if (Application.platform == RuntimePlatform.IPhonePlayer){
    47.             _output();
    48.             //_authplayer();
    49.             _leaderboard();
    50.         }
    51.     }
    52.    
    53.  
    54. }
     
  2. nitinsharma0608

    nitinsharma0608

    Joined:
    Mar 12, 2012
    Posts:
    1
    Hi,

    I want to implement the leaderboard in unity. As per your post,i am not able to figure out where to include the .mm and .h files in unity project?


    Thanx
     
  3. pepefirst

    pepefirst

    Joined:
    Feb 24, 2011
    Posts:
    70
    The .mm and .h files go on the Xcode project after you build it from Unity (File > Build settings and then click button Build). Only the C# script (SomeScript.cs) goes on the Unity project, attached to your main camera.
     
  4. GiusCo

    GiusCo

    Joined:
    Aug 1, 2009
    Posts:
    405
    I need one simple Leaderboard in the Game Center and this small project just appeared to do the trick. Any expert coder willing to investigate the usability of these scripts with Unity 4.x and the latest Xcode? Thanks in advance.
     
  5. toto2003

    toto2003

    Joined:
    Sep 22, 2010
    Posts:
    528
    wow, thanks fawzma for this, i ll test this but i m still a noob
    i ll add you in the credit once my game is released :)