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
    评论
Write a Model class with the following UML specification: +----------------------------------------------+ | Model | +----------------------------------------------+ | - score: int | | - bubbles: ArrayList<IShape> | +----------------------------------------------+ | + Model() | | + getScore(): int | | + addBubble(int w, int h): void | | + moveAll(int dx, int dy): void | | + clearInvisibles(int w, int h): void | | + deleteBubblesAtPoint(int x, int y): void | | + drawAll(Graphics g): void | | + testModel(): void | +----------------------------------------------+ When a new model object is created, the score must be zero and the arraylist must be empty. The getScore method returns as result the current score for the game. The addBubble method adds a new bubble to the arraylist of bubbles. The position of the center of the new bubble is random but must be inside a window of width w and height h (the arguments of the addBubble method), like this: new Bubble((int)(w * Math.random()), (int)(h * Math.random())) The moveAll method moves the positions of all the bubbles in the arraylist of bubbles by the amount dx in the x direction and by the amount dy in the y direction. The clearInvisibles method takes as argument the width w and the height h of the window, and deletes from the arraylist of bubbles any bubble which is not visible in the window anymore. For each bubble which is deleted, the score decreases by 1.The deleteBubblesAtPoint method takes as argument the coordinates (x, y) of a point, and deletes from the arraylist of bubbles any bubble which contains this point (multiple bubbles might contain the point, because bubbles can overlap in the window). For each bubble which is deleted, the score increases by 1. The drawAll method draws all the bubbles in the arraylist of bub
最新发布
05-11

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值