在Cocos2dx中使用Game Center的总结

国内关于Cocos2dx中使用Game Center的教程太少了,而且都缺少很多关键步骤。

我现在使用我的切身经验来总结一下Game Center的使用技巧。

这篇文章中包含了Game Center中排行榜和成就的使用方法、一些关于OC和C++混编的问题,以及测试的技巧。

1.创建OC接口代码文件:NSCGameCenter.h和NSCGameCenter.mm,我们需要说明的是,这两个文件必须要使用Objective-C++ Source的文件类型,现在我把这两个文件的内容贴出来(内容比较多,所以折叠了):

这两个文件不要放到Cocos2dx的Resources文件夹中,因为不应该参与其它平台工程的变异。

这些代码来自于文章,并做了少许修改:http://cocos2d.9tech.cn/news/2013/1202/39024.html

NSCGameCenter.h:
在Cocos2dx中使用Game Center的总结在Cocos2dx中使用Game Center的总结

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

@interface NSCGameCenter : NSObject < GKLeaderboardViewControllerDelegate, GKAchievementViewControllerDelegate, GKMatchmakerViewControllerDelegate, GKMatchDelegate> {
    BOOL gameCenterAvailable;
    BOOL userAuthenticated;
}

@property (assign, readonly) BOOL gameCenterAvailable;
@property (nonatomic, copy) NSString* leaderboardName;
//本地成就字典,用来保存已经下载下来的成就,以避免重复从gamecenter获取成就状态
@property (nonatomic, retain) NSMutableDictionary* achievementDictionary;

+ (NSCGameCenter *)sharedGameCenter;
- (void) authenticateLocalUser;
- (void) registerForAuthenticationNotification;

- (void) showLeaderboard;
- (void) leaderboardViewControllerDidFinish:(GKLeaderboardViewController *)viewController;
//上传分数到Gamecenter
- (void) reportScore:(int64_t)score forCategory:(NSString*)category;
//从gamecenter下载前X个分数
- (void) retrieveTopXScores:(int)number;

- (void) showAchievementboard;
- (void) achievementViewControllerDidFinish:(GKAchievementViewController *)achievementController;
- (void) loadAchievement;
- (void) clearAchievements;
- (void) reportAchievement:(NSString*)id percent:(float)percent;
- (void) unlockAchievement:(GKAchievement*)achievement percent:(float)percent;
- (GKAchievement*) getAchievementForID:(NSString*)id;

@end

View Code
NSCGameCenter.mm:
在Cocos2dx中使用Game Center的总结在Cocos2dx中使用Game Center的总结

#import "NSCGameCenter.h"

@implementation NSCGameCenter
@synthesize gameCenterAvailable;

//静态初始化 对外接口
static NSCGameCenter *sharedHelper = nil;
static UIViewController* currentModalViewController = nil;
+ (NSCGameCenter *) sharedGameCenter {
    if (!sharedHelper) {
        sharedHelper = [[NSCGameCenter alloc] init];
    }
    return sharedHelper;
}

//用于验证
- (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 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;
    }
}

- (void)authenticateLocalUser {
    if (!gameCenterAvailable) return;
    NSLog(@"Authenticating local user...");
    if ([GKLocalPlayer localPlayer].authenticated == NO) {
        GKLocalPlayer *localPlayer = [GKLocalPlayer localPlayer];
        [localPlayer setAuthenticateHandler:(^(UIViewController* viewcontroller, NSError *error) {
            if(localPlayer.isAuthenticated)
            {
                NSLog(@"LOGIN SUCCEED!");
            }else{
                NSLog(@"LOGIN FAILED!");
            }})];

    } else {
        NSLog(@"Already authenticated!");
    }

}

- (void) registerForAuthenticationNotification
{
    NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
    [nc addObserver:self
           selector:@selector(authenticationChanged)
               name:GKPlayerAuthenticationDidChangeNotificationName
             object:nil];
}

//显示排行榜
- (void) showLeaderboard
{
    if (!gameCenterAvailable) return;

    GKLeaderboardViewController *leaderboardController = [[GKLeaderboardViewController alloc] init];
    if (leaderboardController != nil) {
        leaderboardController.leaderboardDelegate = self;

        UIWindow *window = [[UIApplication sharedApplication] keyWindow];
        currentModalViewController = [[UIViewController alloc] init];
        [window addSubview:currentModalViewController.view];
        [currentModalViewController presentModalViewController:leaderboardController animated:YES];
    }

}

//关闭排行榜回调
- (void)leaderboardViewControllerDidFinish:(GKLeaderboardViewController *)viewController{
    if(currentModalViewController !=nil){
        [currentModalViewController dismissModalViewControllerAnimated:NO];
        [currentModalViewController release];
        [currentModalViewController.view removeFromSuperview];
        currentModalViewController = nil;
    }
}

//上传分数到排行榜
- (void) reportScore: (int64_t) score forCategory: (NSString*) category
{
    GKScore *scoreReporter = [[[GKScore alloc] initWithCategory:category] autorelease];
    scoreReporter.value = score;

    [scoreReporter reportScoreWithCompletionHandler:^(NSError *error) {
        if (error != nil)
        {
            NSLog(@"上传分数出错.");
        }
        else
        {
            NSLog(@"上传分数成功");
        }
    }];
}

//下载分数
- (void) retrieveTopXScores:(int)number
{
    GKLeaderboard *leaderboardRequest = [[GKLeaderboard alloc] init];
    if (leaderboardRequest != nil)
    {
        leaderboardRequest.playerScope = GKLeaderboardPlayerScopeGlobal;
        leaderboardRequest.timeScope = GKLeaderboardTimeScopeAllTime;
        leaderboardRequest.range = NSMakeRange(1,number);
        leaderboardRequest.category = _leaderboardName;
        [leaderboardRequest loadScoresWithCompletionHandler: ^(NSArray *scores, NSError *error) {
            if (error != nil){
                // handle the error.
                NSLog(@"下载失败");
            }
            if (scores != nil){
                // process the score information.
                NSLog(@"下载成功....");
                //NSArray *tempScore = [NSArray arrayWithArray:leaderboardRequest.scores];
                //for (GKScore *obj in tempScore) {
                //    NSLog(@"    playerID            : %@",obj.playerID);
                //    NSLog(@"    category            : %@",obj.category);
                //    NSLog(@"    date                : %@",obj.date);
                //    NSLog(@"    formattedValue    : %@",obj.formattedValue);
                //    NSLog(@"    value                : %d",obj.value);
                //    NSLog(@"    rank                : %d",obj.rank);
                //    NSLog(@"**************************************");
                //}
            }
        }];
    }
}

//汇报成就
//通过ID汇报成就
- (void) reportAchievement:(NSString*)id percent:(float)percent
{
    if ( !gameCenterAvailable ) {
        NSLog(@"ERROR: GameCenter is not available currently");
        return;
    }

    GKAchievement* achievement = [[[GKAchievement alloc] initWithIdentifier:id] autorelease];
    [self unlockAchievement:achievement percent:percent];
}

//通过成就指针汇报成就
- (void) unlockAchievement:(GKAchievement *)achievement percent:(float)percent
{
    if ( achievement != nil )
    {
        achievement.percentComplete = percent;
        achievement.showsCompletionBanner = YES;
        [achievement reportAchievementWithCompletionHandler:^(NSError* error){
            if ( error != nil)
            {
                NSLog(@"上传成就错误,错误提示为n%@", error);
            }
            else
            {
                NSLog(@"上传成就成功n");
                [self displayAchievement:achievement];
            }
        }];
    }
}

//显示成就
- (void) showAchievementboard
{
    if (!gameCenterAvailable) return;

    GKAchievementViewController *achievementController = [[GKAchievementViewController alloc] init];
    if (achievementController != nil) {
        achievementController.achievementDelegate = self;

        UIWindow *window = [[UIApplication sharedApplication] keyWindow];
        currentModalViewController = [[UIViewController alloc] init];
        [window addSubview:currentModalViewController.view];
        [currentModalViewController presentModalViewController:achievementController animated:YES];
    }

}

//关闭成就回调
- (void)achievementViewControllerDidFinish:(GKAchievementViewController *)viewController{
    if(currentModalViewController !=nil){
        [currentModalViewController dismissModalViewControllerAnimated:NO];
        [currentModalViewController release];
        [currentModalViewController.view removeFromSuperview];
        currentModalViewController = nil;
    }
}

//打印某个成就
- (void) displayAchievement:(GKAchievement*)achievement
{
    if ( achievement == nil) return;

    NSLog(@"completed:%d", achievement.completed);
    NSLog(@"lastReportDate:%@", achievement.lastReportedDate);
    NSLog(@"percentComplete:%f", achievement.percentComplete);
    NSLog(@"identifier:%@", achievement.identifier);
}

//加载所有成就。经测试,只能获取到已经上传过的成就状态。
- (void) loadAchievement
{
    if ( self.achievementDictionary == nil )
    {
        self.achievementDictionary = [[NSMutableDictionary alloc] init];
    }
    [GKAchievement loadAchievementsWithCompletionHandler:^(NSArray* achievements, NSError* error){
        if ( error == nil && achievements != nil )
        {
            NSArray* tempArray = [NSArray arrayWithArray:achievements];
            for(GKAchievement* tempAchievement in tempArray)
            {
                [self.achievementDictionary setObject:tempAchievement
                                               forKey:tempAchievement.identifier];
                [self displayAchievement:tempAchievement];
            }
        }
    }];

}

//通过成就id生成成就。首先从本地成就字典查询,查询不到则生成一个。
- (GKAchievement*) getAchievementForID: (NSString*) id
{
    if ( self.achievementDictionary == nil )
    {
        self.achievementDictionary = [[NSMutableDictionary alloc] init];
    }
    GKAchievement *achievement = [self.achievementDictionary objectForKey:id];
    if (achievement == nil)
    {
        achievement = [[[GKAchievement alloc] initWithIdentifier:id] autorelease];
        [self.achievementDictionary setObject:achievement
                                       forKey:achievement.identifier];
    }
    [self displayAchievement:achievement];
    return [[achievement retain] autorelease];
}

//初始化所有成就状态。经测试,这段代码暂时无效。
- (void) clearAchievements
{
    NSEnumerator* enumerator = [self.achievementDictionary objectEnumerator];
    for(NSObject* obj in enumerator)
    {
        [self unlockAchievement:(GKAchievement*)obj percent:0.0];
    }
}

@end

View Code
2.在AppController.mm中添加引用,并使用当前用户登陆到Game Center:

在文件开头加入以下代码:

#import "NSCGameCenter.h"

在didFinishLaunchingWithOptions中添加以下代码以登陆:

[[NSCGameCenter sharedGameCenter] authenticateLocalUser];

注意:需要特别说明的是,NSCGameCenter.h的引用,千万不能添加到头文件"*.h"中,这样会出现很多的错误,必须要添加到".mm"文件中,并且但凡要使用NSCGameCenter.h的文件都必须是Objective-C++ Source类型的,因此下面使用提交分数等操作的C++文件也必须改为Objective-C++ Source类型的文件。

3.在Cocosdx中的类文件中添加引用,并使用Game Center的相关功能

在这这一步骤中首先要做的事是修改文件类型,见上方的“注意”。

首先我们在类文件例如"sceneStarter.mm"(注意不是"sceneStarter.h")中添加:

#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
#include "NSCGameCenter.h"
#endif

此时,我们将会发现工程中出现了许多错误,例如"Reference to 'Size' is ambiguous."或者"Reference to 'Rect' is ambiguous."等等,这是因为Cocos2dx中定义的类型与Foundation中定义的类型名称相同而发生冲突,因此我们需要为这些类型加上命名空间:

//Size类型名发生冲突:
Size screenSize; //Reference to 'Size' is ambiguous.
//应该为其添加命名空间:
cocos2d::Size screenSize;

到这一步,错误都调试OK了,可以开始使用Game Center提供的功能了,我们再次仅以Leaderboard为例:

(1)打开排行榜界面:

[[NSCGameCenter sharedGameCenter] showLeaderboard];

(2)提交一个分数:

这段代码的参数需要解释的是,reportScore代表分数值,forCategory代表排行榜名称。

[[NSCGameCenter sharedGameCenter] reportScore:1000 forCategory:@"Global_Learderboard"];

代码是如此的简单,谢谢苹果带我装逼带我飞。

4.到此,代码的测试就完成了。但是我们还需要真机调试,我们需要在iPhone或iPad上进行一些简单地设置:

首先,打开"设置"->"Game Center",将"沙盒"开关打开,并重新输入密码登陆即可开始沙盒测试。

但是需要注意,仅有以"Signed Distribution Build"方式编译的App需要进行上述操作(参考Game Center Programming Guide),如果不进行该操作,将会出现以下错误:

Game Center unavailable(player is not signed in).

原文链接: https://www.cnblogs.com/ferryseling/p/4634673.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/218915

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年2月13日 上午10:22
下一篇 2023年2月13日 上午10:22

相关推荐