2dx game center 简介

Game Center是Apple iOS平台的游戏平台,通过Game Center应用程序可以登陆进入平台进行游戏管理和好友管理,每一款游戏可以借助平台的服务器创建自己的排行和成绩榜,玩家也可以在Game Center平台中邀请好友参加某一款游戏,实现好友之间的多人对战。Game Center的功能和显示类库在GameKit框架中,集成了GameKit API的游戏,可以在游戏内部登陆Game Center服务器,实现等同于在平台应用内的操作。开发者可以按照游戏的风格自定义邀请好友、排行榜的显示界面,也可以调用GameKit的标准显示界面。

我个人认为Game Center更高的价值在于它提供了一套支持多人实时游戏的API,开发者可以依靠Game Center提供的服务器实现多人共享一个Match对象,完成多人在线游戏。也可以通过自己的服务器来完成更为复杂的在线游戏。

Game Center的核心类与功能

Game Center的类名都是以GK开头,比如玩家信息在GKPlayer和GKLocalPlayer里,排行榜的标准显示界面是GKLeaderboardViewController,排行榜的信息在GKLeaderboard里。比赛的信息在GKMatch里,申请比赛的标准窗口是GKMatchmakerViewController类,等等。这些在接下来的章节中会慢慢地介绍。

登陆Game Center

Game Center的用户系统与Apple的帐号是完全分开的,玩家可以自行创建若干个Game Center帐号。帐号可以在Game Center的应用中登陆,或者在运行含有GameKit API的游戏时,在需要登陆的时候通过弹出的登陆窗口来登陆。从开发者的角度来说,需要首先判断玩家的设备是否支持Game Center的功能,然后尽可能早的登陆Game Center。登陆后的账号信息会保存在一个静态的GKLocalPlayer实例中:

//获取静态实例localPlayer,然后使用authenticateWithCompletionHandler登陆 GKLocalPlayer *localPlayer = [GKLocalPlayer localPlayer]; [localPlayer authenticateWithCompletionHandler:^(NSError *error) { GKLocalPlayer *lp = [GKLocalPlayer localPlayer]; if(lp.isAuthenticated){ //登陆成功, }else{ //登陆失败 } }];

注意:如果在登陆成功之前使用GameKit的其他类,很可能会出现未知的错误,所以建议越早登陆越好。

通过ANE实现Native与ActionScript的基础通信

当用户登陆Game Center之后,本地玩家的用户信息将会存储在localPlayer对象中,包括玩家ID,玩家显示名称,好友列表等等。这些信息有的需要显示在Flash创建的前端界面中。作为ANE的开发者,需要掌握如何从OBJC中向Flash返回函数值:

FREObject authenticate(FREContext ctx, void* funcData, uint32_t argc, FREObject argv[]) { GKLocalPlayer *localPlayer = [GKLocalPlayer localPlayer]; [localPlayer authenticateWithCompletionHandler:^(NSError *error) { GKLocalPlayer *lp = [GKLocalPlayer localPlayer]; if(lp.isAuthenticated){ //OBJC中的字符串类型是NSString,格式如@"a" NSMutableString* retXML = [[NSMutableString alloc] initWithString:@"<p>"]; [retXML appendFormat:@"<i>%@</i>",lp.playerID]; [retXML appendFormat:@"<a>%@</a>",lp.alias]; [retXML appendFormat:@"</p>"];   //向Flash派发事件的参数字符串类型是uint8_t,在ActionScript中注册StatusEvent.STATUS事件的侦听器, //"authenticate_status_changed"会保存在StatusEvent.code里,retXML会保存在StatusEvent.level里。 FREDispatchStatusEventAsync(g_ctx, (const uint8_t*)"authenticate_status_changed",(const uint8_t*)[retXML UTF8String]); }else{ FREDispatchStatusEventAsync(g_ctx, (const uint8_t*)"authenticate_status_changed",(const uint8_t*)""); } }]; return nil; }

上面这个例子是一个FREFunction的函数体,也就是可以被Flash调用的FRE API(如果你对如何在Flash端调用Native函数还不是很清楚,我建议你先看看这篇文章)。例子里用一个retXML来保存玩家的基本信息,然后通过FREDispatchStatusEventAsync来派发给Flash。这是Native向AS的一个标准的事件派发实例。

下面是在FlashRuntimeExtension.h中对FREFunction的定义:

typedef FREObject (*FREFunction)( FREContext ctx, void* functionData, uint32_t argc, FREObject argv[] );

前三个参数在函数执行的时候基本不用考虑,我们只要注意第四个就可以了。Flash调用Native函数的时候,参数寄存在argv这个数组中,类型是FREObject。比如下面的这个例子,是从Flash端调用Native的alert窗口,并且显示标题和内容。例子的核心在于如何从argv中取出参数中的值。

FREObject alert(FREContext ctx,void* funcData, uint32_t argc, FREObject argv[]){ //先定义两个变量,用来寄存标题和内容。 const uint8_t* title = nil; const uint8_t* msg = nil; uint32_t len = -1; //使用FREGetObjectAsUTF8,从argv中取出相应的参数值,然后存放到title和msg对应的指针中。 //这是通过FRE API实现从FREObject中向Native变量赋值的典型形式。 FREGetObjectAsUTF8(argv[0], &len, &title); FREGetObjectAsUTF8(argv[1], &len, &msg); UIAlertView *alert = [[UIAlertView alloc] initWithTitle:[NSString stringWithUTF8String:(const char *)title] message:[NSString stringWithUTF8String:(const char *)msg] delegate:nil cancelButtonTitle:@"Cancel" otherButtonTitles:nil,nil]; [alert show]; return nil; }

其实不管是什么类型,字符串、数字、布尔职甚至数组、位图对象等等,只要是从Flash传递过来的,或者是传递给Flash去的,都必须定义为FREObject类型。比如下面这个例子是判断设备是否支持Game Center:

FREObject isGCAvailable(FREContext ctx, void* funcData, uint32_t argc, FREObject argv[]) { BOOL localPlayerClassAvailable = (NSClassFromString(@"GKLocalPlayer")) != nil; // Game Center必须运行在iOS 4.1以上的环境。 NSString *reqSysVer = @"4.1"; NSString *currSysVer = [[UIDevice currentDevice] systemVersion]; BOOL osVersionSupported = ([currSysVer compare:reqSysVer options:NSNumericSearch] != NSOrderedAscending); // 定义一个准备回传给Flash的类型。 FREObject reVal; //通过FRE的FRENewObject... 来给FREObject赋值。&reVal是对reVal指针的操作, //可以将(localPlayerClassAvailable && osVersionSupported)的值作为ActionScript的布尔对象赋给变量reVal FRENewObjectFromBool((localPlayerClassAvailable && osVersionSupported),&reVal); return reVal; };
ActionScript与Native之间的数据通讯
图1 ActionScript与Native之间的数据通讯

标准Leader board的显示与移除

很多集成Game Center的游戏都只是为了显示玩家的得分以及排行,要实现这个功能,须要首先在iTunesConnect里启用Game Center并定义排行榜。这个部分的功能比较简单,作为技术文章我就不做具体的介绍了。

GameKit提供了一个现成的Leader board界面,调用这个界面即可以展示该应用的排行榜。下面就是如何调用这个标准的界面:

FREObject showLeaderBoard(FREContext ctx, void* funcData, uint32_t argc, FREObject argv[]) { GKLeaderboardViewController *leaderboardController = [[GKLeaderboardViewController alloc] init]; if (leaderboardController != nil) { const uint8_t* category = nil; uint32_t len = -1; leaderboardController.leaderboardDelegate = observer; showModalViewController(leaderboardController); }else{ } return nil; }

iOS SDK中很多标准的界面都是继承了UIViewController,但是AIR应用并不是建立在UIViewController的架构之上的,所以如何在AIR的应用中显示UIViewController就是一个知识点:

void showModalViewController(UIViewController* viewController){ if(currentModalViewController!=nil){ dismissModalViewController(currentModalViewController); } //找到AIR应用的最顶层View对象,一个UIWindow对象。 UIWindow *window = [[UIApplication sharedApplication] keyWindow]; //建立一个空的UIViewController对象,用来做显示Leader board的容器 UIViewController *parentViewController = [[UIViewController alloc] init]; //将容器加在AIR的root层View对象之上。 [window addSubview:parentViewController.view]; //用显示独占窗口的方式显示Leader board,因为presentModalViewController这个方法只存在于UIViewController类中, //这就是为什么使用一个容器来作为中间层。 [parentViewController presentModalViewController:viewController animated:YES]; currentModalViewController = viewController; }

打开Leader board之后,须要给leader board窗口添加一个回调函数Delegate,用来接收关闭窗口的事件。这个Delegate类是GKLeaderboardViewControllerDelegate,接收关闭窗口的方法是leaderboardViewControllerDidFinish。在 OBJC中实现Delegate的定义,其实等同于ActionScript中对接口的实现。比如自定义一个MyDelegate类,在MyDelegate.h里须要用下面的代码进行声明:

@interface MyDelegate : NSObject <GKLeaderboardViewControllerDelegate>{ } - (void)leaderboardViewControllerDidFinish:(GKLeaderboardViewController *)viewController; @end

然后在MyDelegate.m里实现方法的函数体:

- (void)leaderboardViewControllerDidFinish:(GKLeaderboardViewController *)viewController{ dismissModalViewController(viewController); }

移除UIViewController的代码也非常易懂:

void dismissModalViewController(UIViewController* viewController){ if(viewController !=nil){ UIViewController *parentViewController = [viewController parentViewController]; [parentViewController dismissModalViewControllerAnimated:NO]; [parentViewController.view removeFromSuperview]; currentModalViewController = nil; } }

如何上传游戏得分

登陆用户只能上传自己的得分,一个应用可能包含了多个排行,每一个排行都有一个category的ID,在上传得分的时候必须要指明这个ID。

FREObject reportScore(FREContext ctx,void* funcData, uint32_t argc, FREObject argv[]){ const uint8_t* category = nil; uint32_t len = -1; if(FREGetObjectAsUTF8(argv[0], &len, &category) == FRE_OK){ GKScore *scoreReporter = [[GKScore alloc] initWithCategory:[NSString stringWithUTF8String:(const char *) category]]; scoreReporter.value = 1010; [scoreReporter reportScoreWithCompletionHandler:^(NSError *error) { if (error != nil) { }else{ } }]; } return nil; }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值