你好,歡迎來到IOS教程網

 Ios教程網 >> IOS編程開發 >> IOS開發綜合 >> iOS - 集成game center (leader board)

iOS - 集成game center (leader board)

編輯:IOS開發綜合

最近又一次用到game center裡面的leader board。其實這個事情很簡單,只是很容易忘記。所以就打算寫下來。


iTunes Connect上創建app,然後啟用game center

創建app就省略了,等創建成功後,不需要提交。我們就可以設置game center了。

首先點擊新建的app,找到Game Center,如圖

\


點擊進入具體的game center設置,可以添加一些項目。很是簡單,基本上都有提示,需要注意的是排行榜id,得搞個獨立的,不要重復。這個id在代碼裡面需要使用。

就這麼簡單的搞幾下,game center就啟用了。

\


在代碼中引入game center

在xcode的工程裡面打開game center,

\



<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD4KPHA+1rG907Tyv6q+zdDQo6y40L71aW9zv6q3otS9wLTUvcm1uc/By6Osuse6x6GjPC9wPgo8cD6908/CwLS+zcrHvt/M5bXEtPrC68q1z9bBy6GjPC9wPgo8cD48YnI+CjwvcD4KPHA+PHN0cm9uZz60+sLryrXP1jwvc3Ryb25nPjwvcD4KPHA+ytfPyNTaus/KyrXEtdi3vcztvNPI58/CtPrC66O6zaizo8rHPC9wPgo8cD4tIChCT09MKWFwcGxpY2F0aW9uOihVSUFwcGxpY2F0aW9uICopYXBwbGljYXRpb24gZGlkRmluaXNoTGF1bmNoaW5nV2l0aE9wdGlvbnM6KE5TRGljdGlvbmFyeQogKilsYXVuY2hPcHRpb25zPC9wPgo8cD48cHJlIGNsYXNzPQ=="brush:java;">double ver = [[UIDevice currentDevice].systemVersion doubleValue]; if (ver < 6.0) { [[GKLocalPlayer localPlayer] authenticateWithCompletionHandler:^(NSError *error) { }]; } else { [[GKLocalPlayer localPlayer] setAuthenticateHandler:(^(UIViewController* viewcontroller, NSError *error) { })]; } NSNotificationCenter* ns = [NSNotificationCenter defaultCenter]; [ns addObserver:self selector:@selector(authenticationChanged) name:GKPlayerAuthenticationDidChangeNotificationName object:nil]; 我們給game center增加了一個觀察者,所以就需要在self裡面提供一個函數。這是一個回調函數,如果用戶沒有登錄game center,那麼就會跑到下面,如果登陸了就會跑到上面。

- (void) authenticationChanged
{
    if ([GKLocalPlayer localPlayer].isAuthenticated) {
        NSLog(@"authenticationChanged, authenticated");
        
        
        
    }
    else
    {
        
        NSLog(@"authenticationChanged, Not authenticated");
    }
}

接下來就是提交和顯示leader board了。具體的說明蘋果的官網上說的很清楚。我這裡在網上找到一個封裝的源代碼,自己稍微修改了一下。具體代碼看最後面(附)。這裡主要介紹使用流程。先增加一個屬性。

@property (readwrite, retain) PlayerModel * player;
再增加一個函數,如:

- (void) updatePlayer
{
    
    if (!self.player || ![self.player.currentPlayerID isEqualToString:[GKLocalPlayer localPlayer].playerID]) {
        
        [self.player release];
        
        self.player = [[PlayerModel alloc] init];
    }
    [[self player] loadStoredScores];
}
這個函數會在authenticationChanged裡面被調到。

- (void) authenticationChanged
{
    if ([GKLocalPlayer localPlayer].isAuthenticated) {
        NSLog(@"authenticationChanged, authenticated");
        
        [self updatePlayer];
    }
    else
    {
        NSLog(@"authenticationChanged, Not authenticated");
    }
}
updatePlayer這個函數比較關鍵。

它支持多用戶,如果是第一次登陸game center,那麼就創建一個對象,如果是換了個用戶登錄,那麼就把之前的釋放,然後創建一個新的對象。然後調用loadStoredScore.

loadStoredScore會從本地文件裡面讀取需要傳送的分數,並且往game center服務器傳。

上面這段代碼的意思就是app起來後,authenticationChanged被調用了,如果是登錄的狀態,那麼就會創建一個PlayerModel對象。如果有需要上傳的數據,那麼就讀取並且嘗試上傳。

其實這是個保護措施,後面會講到為什麼需要這麼做。


接下來就看看如果在游戲中即時上傳數據。

首先增加一個函數,這個函數就是往服務器發送數據。self.player submitScore,這個函數會在後面看到。有了這個函數,我們在游戲或者應用的某個地方可以調用往服務器發送數據了。LEADERBOARD_DISTANCE的值就是上面connect裡面創建的那個排行榜id。

- (void) storeScore:(NSNumber *)distance
{
    if (!self.player)
        return;
    
    int64_t score64 =  [distance longLongValue];
    GKScore * submitScore = [[GKScore alloc] initWithCategory:LEADERBOARD_DISTANCE];
    [submitScore setValue:score64];
    [self.player submitScore:submitScore];
    [submitScore release];
}

ok,就這麼簡單。現在就大概講講PlayerModel的原理。因為我們在提交的時候往往會因為網絡原因而失敗,特別在中國。所以,PlayerModel裡面就提交了一個機制,如果提交失敗,就把要提交的數據保存到本地文件,在合適的時候再嘗試提交。

- (void)submitScore:(GKScore *)score 
{
    if ([GKLocalPlayer localPlayer].authenticated) {
        if (!score.value) {
            // Unable to validate data. 
            return;
        }
        
        // Store the scores if there is an error. 
        [score reportScoreWithCompletionHandler:^(NSError *error){
            if (!error || (![error code] && ![error domain])) {
                // Score submitted correctly. Resubmit others
                [self resubmitStoredScores];
            } else {
                // Store score for next authentication. 
                [self storeScore:score];
            }
        }];
    } 
}
這個函數的主要意思就是,先嘗試提交數據,如果成功,那麼隨便提交一下其他的數據(可能之前提交失敗了)。如果失敗,那麼就把數據保存下來[self storeScore: score],保存到一個array,並且寫入本地文件。這樣就有機會在其他地方再提交一次。完整代碼看後面。

現在就看看如果在app裡面顯示leader board。看下面的代碼gameCenterAuthenticationComplete是我內部使用的一個bool,用來標記用戶是否登錄了game center。調用一下這個代碼,就會顯示iOS的game center。

- (void) showGameCenter
{
    if (gameCenterAuthenticationComplete) {
        GKLeaderboardViewController * leaderboardViewController = [[GKLeaderboardViewController alloc] init];
        [leaderboardViewController setCategory:LEADERBOARD_DISTANCE];
        [leaderboardViewController setLeaderboardDelegate:_viewController];
        [self.viewController presentModalViewController:leaderboardViewController  animated:YES];
        [leaderboardViewController release];
    }
}


附,完整PlayerModle代碼:

header file:

#import 
#import 

@interface PlayerModel : NSObject {
	NSLock *writeLock;
}

@property (readonly, nonatomic) NSString* currentPlayerID;
@property (readonly, nonatomic) NSString *storedScoresFilename;
@property (readonly, nonatomic) NSMutableArray * storedScores;

// Store score for submission at a later time.
- (void)storeScore:(GKScore *)score ;

// Submit stored scores and remove from stored scores array.
- (void)resubmitStoredScores;

// Save store on disk. 
- (void)writeStoredScore;

// Load stored scores from disk.
- (void)loadStoredScores;

// Try to submit score, store on failure.
- (void)submitScore:(GKScore *)score ;

@end


m file:

#import "PlayerModel.h"

@implementation PlayerModel

@synthesize storedScores,
            currentPlayerID,
            storedScoresFilename;

- (id)init
{
    self = [super init];
    if (self) {
        currentPlayerID = [[NSString stringWithFormat:@"%@", [GKLocalPlayer localPlayer].playerID] retain];
        NSString* path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
        storedScoresFilename = [[NSString alloc] initWithFormat:@"%@/%@.storedScores.plist",path, currentPlayerID];
        writeLock = [[NSLock alloc] init];
    }
    return self;
}

- (void)dealloc
{
    [storedScores release];
    [writeLock release];
    [storedScoresFilename release];
    [currentPlayerID release];
    
    [super dealloc];
}

// Attempt to resubmit the scores.
- (void)resubmitStoredScores
{
    if (storedScores) {
        // Keeping an index prevents new entries to be added when the network is down 
        int index = (int)[storedScores count] - 1;
        while( index >= 0 ) {
            GKScore * score = [storedScores objectAtIndex:index];
            [self submitScore:score];
            [storedScores removeObjectAtIndex:index];
            index--;
        }
        [self writeStoredScore];
    }
}

// Load stored scores from disk.
- (void)loadStoredScores
{
    NSArray *  unarchivedObj = [NSKeyedUnarchiver unarchiveObjectWithFile:storedScoresFilename];
    
    if (unarchivedObj) {
        storedScores = [[NSMutableArray alloc] initWithArray:unarchivedObj];
        [self resubmitStoredScores];
    } else {
        storedScores = [[NSMutableArray alloc] init];
    }
}


// Save stored scores to file. 
- (void)writeStoredScore
{
    [writeLock lock];
    NSData * archivedScore = [NSKeyedArchiver archivedDataWithRootObject:storedScores];
    NSError * error;
    [archivedScore writeToFile:storedScoresFilename options:NSDataWritingFileProtectionNone error:&error];
    if (error) {
        //  Error saving file, handle accordingly 
    }
    [writeLock unlock];
}

// Store score for submission at a later time.
- (void)storeScore:(GKScore *)score 
{
    [storedScores addObject:score];
    [self writeStoredScore];
}

// Attempt to submit a score. On an error store it for a later time.
- (void)submitScore:(GKScore *)score 
{
    if ([GKLocalPlayer localPlayer].authenticated) {
        if (!score.value) {
            // Unable to validate data. 
            return;
        }
        
        // Store the scores if there is an error. 
        [score reportScoreWithCompletionHandler:^(NSError *error){
            if (!error || (![error code] && ![error domain])) {
                // Score submitted correctly. Resubmit others
                [self resubmitStoredScores];
            } else {
                // Store score for next authentication. 
                [self storeScore:score];
            }
        }];
    } 
}

@end













  1. 上一頁:
  2. 下一頁:
蘋果刷機越獄教程| IOS教程問題解答| IOS技巧綜合| IOS7技巧| IOS8教程
Copyright © Ios教程網 All Rights Reserved