主页(http://www.zhonghuagame.com):iOS游戏平台Game Center成就显示设置指南
新闻中心 > 产业
游戏邦 2011年12月12日 22:00
iOS游戏平台Game Center成就显示设置指南
我的某个项目有部分美工工作尚未完成,我决定先着手整合Game Center。此指南旨在说明当成就被发送至Game Center时,如何在游戏中呈现成就内容。我会深入探讨如何融入成就图像,这里还会涉及到一些简单框架的运用。
在此,我默认你的应用已植入Game Center系统。通过运用《Learning Cocos2D》、Ray Wenderlich等教程传授的方法,我得以在短短几小时内就运行应用。
通过用户身份验证,设置好系列iTunes Connect成就后,你定会希望在获得新成就时呈现“Achievement Attained”信息。同样,这不同于仅仅展示成就视窗,还会呈现玩家获得的所有成就。我们希望呈现若干通知消息。
苹果iOS 5已给予我们预先打包好的API调用,这会在玩家完成某项成就时展示成就横幅。下面是最简单的方式:
- (void)sendAchievement:(GKAchievement *)achievement {
achievement.percentComplete = 100.0; //Indicates the achievement is done
achievement.showsCompletionBanner = YES; //Indicate that a banner should be shown
[achievement reportAchievementWithCompletionHandler:
^(NSError *error) {
dispatch_async(dispatch_get_main_queue(), ^(void)
{
if (error == NULL) {
NSLog(@"Successfully sent archievement!");
} else {
NSLog(@"Achievement failed to send... will try again \
later. Reason: %@", error.localizedDescription);
}
});
}];
}
此代码根据标识符(你在iTunes中设定的内容)创建成就目标,你将完成状态设置成100%,将“showsCompletionBanner”属性设置成YES,提交给苹果。新iOS属性“showsCompletionBanner”,其默认设置是NO,但若将其调整成YES,屏幕就呈现包含成就标题和描述的漂亮横幅,如下所示。
但此方式存在局限性。首先,其运用普通Game Center图标,而非从游戏成就中下载来的图像。更糟的是,若玩家同时获得两项成就,页面只会呈现一个,我觉得这非常糟糕。最后,这只锁定iOS 5的API调用,所以会导致任何未搭载iOS 5系统的设备崩溃。
所以为修复这些问题,我们将不采用“showsCompletionBanner”属性,而是执行我们自己的通知,或者更准确地说借鉴和修改前人所使用的代码。
首先,我借鉴Type One Error所展示的优秀代码,从https://github.com/typeoneerror/GKAchievementNotification中抓取一些代码植入自己的项目。我们将采用GKAchievementNotification和GKAchievementHandler类,同时进行相应更新和修改。首先,若你在游戏中运用ARC,快速扫描代码,移除那些发行、保留和自动发行代码属性。若你不想进行扫描,试着将文件放入项目及修复不符编译程序的内容,然后再创建内容。
Type One Error类将展示类似于iOS 5所呈现的通知内容,但代码需获悉成就标题和描述是什么。为实现这点,你需要嵌入“showsCompletionBanner”目标。
GKAchievementDescription目标的优点是它们已根据用户语言设定进行本土化,因此采用此方式不存在任何本土化问题。
其弊端在于你无法只加载一个成就描述,你需要加载所有内容。我认为进行此操作的最佳时间是用户已在应用上认证Game Center,此时你需要通过异步调用获得这些消息。值得欣慰的是,苹果在此设有API调用,我将此放置在用户认证访问的CompletionHandler中。
若你采用Ray Wenderlich网站的代码,那么你就既能够运用此方法,又拥有新方法。将NSMutableDictionary * self.achievementsDescDictionary添加至所有处理游戏Game Center代码的类(游戏邦注:它会在随后的体验中存储成就数据)。
- (void)authenticateLocalUser {
if (!gameCenterAvailable) return;
NSLog(@”Authenticating local user…”);
if ([GKLocalPlayer localPlayer].authenticated == NO) {
[[GKLocalPlayer localPlayer]
authenticateWithCompletionHandler:^(NSError *error) {
if([GKLocalPlayer localPlayer].isAuthenticated){
[self retrieveAchievmentMetadata]; //Here is the new code
}
}];
}
}
//Here is the new method。
- (void) retrieveAchievmentMetadata
{
self.achievementsDescDictionary = [[NSMutableDictionary alloc] initWithCapacity:2];
[GKAchievementDescription loadAchievementDescriptionsWithCompletionHandler:
^(NSArray *descriptions, NSError *error) {
if (error != nil) {
NSLog(@"Error %@", error);
} else {
if (descriptions != nil){
for (GKAchievementDescription* a in descriptions) {
[achievementsDescDictionary setObject: a forKey: a.identifier];
}
}
}
}];
}
“retrieveAchievmentMetadata”方法会初始化所有信息库,然后调用游戏所有成就描述,进行循环,将它们添加至信息库。这属于异步调用,所以不应减缓游戏或项目的启动。
现在我们握有各成就的标题和描述,因此能够修改原始代码创造iOS 4/5的善意通知,其将通过Type One Error代码连续展示所有成就。
- (void)reportAchievement:(NSString *)identifier
percentComplete:(double)percentComplete {
GKAchievement* achievement = [[GKAchievement alloc]
initWithIdentifier:identifier];
achievement.percentComplete = percentComplete;
if (percentComplete == 100.0) {
//Show banners manually
GKAchievementDescription *desc = [achievementsDescDictionary objectForKey:identifier]; //Update pull achievement description for dictionary
[[GKAchievementHandler defaultHandler] notifyAchievement:desc]; //Display to user
}
[achievementsToReport addObject:achievement]; //Queue up the achievement to be sent
[self save];
if (!gameCenterAvailable || !userAuthenticated) return;
[self sendAchievement:achievement]; //Try to send achievement
}
- (void)sendAchievement:(GKAchievement *)achievement {
[achievement reportAchievementWithCompletionHandler:
^(NSError *error) {
dispatch_async(dispatch_get_main_queue(), ^(void)
{
if (error == NULL) {
NSLog(@"Successfully sent archievement!");
[achievementsToReport removeObject:achievement]; //Remove Achievement from queue。
} else {
NSLog(@”Achievement failed to send… will try again \
later. Reason: %@”, error.localizedDescription);
}
});
}];
}
另外查看成就是否100%完整,若是如此,提取正确成就描述目标,向玩家展示。然后继续告知苹果新成就,若游戏属于风景类型,其外观将类似如此。
但我觉得若能呈现成就图像而非默认图像会更好。所以为达到此目的,将通知的部分代码更新成如下内容:
if (percentComplete == 100.0) {
//Show banners manually
GKAchievementDescription *desc = [achievementsDescDictionary objectForKey:identifier];
[desc loadImageWithCompletionHandler:^(UIImage *image, NSError *error) {
if (error == nil)
{
[[GKAchievementHandler defaultHandler] setImage:desc.image]; //If image found, updates the image to the achievement image。
}
[[GKAchievementHandler defaultHandler] notifyAchievement:desc];
}];
}
代码处在完成处理模块之中,因此只有处理程序返回时,它才会执行。若其返回图像,那么通知就会更新成图像,然后向玩家展示。
这里包含临时美工元素。我之前有说过美工工作有些滞后。通过创造性地运用此方式,你会发现若你制作的是款风景游戏,通知就会显示在侧边。想要解决此风景问题,你需要完成两项工作,调整框架和循环。
在“GKAchievementHandler”类中找到“notifyAchievement”,更新为:
- (void)notifyAchievement:(GKAchievementDescription *)achievement
{
GKAchievementNotification *notification = [[GKAchievementNotification alloc] initWithAchievementDescription:achievement];
notification.frame = kGKAchievementFrameStart;
notification.handlerDelegate = self;
//Adjusting rotation。
if ([[UIApplication sharedApplication] statusBarOrientation] == UIInterfaceOrientationLandscapeLeft) {
notification.transform = CGAffineTransformRotate(notification.transform, degreesToRadian(-90));
} else {
notification.transform = CGAffineTransformRotate(notification.transform, degreesToRadian(90));
}
notification.frame = kGKAchievementFrameStartLandscape; //Update the frame, you need to create this definition。
[_queue addObject:notification];
if ([_queue count] == 1)
{
[self displayNotification:notification];
}
}
必要时候调整“animateIn”和“animateOut”。我发现这些框架作用显著:
#define kGKAchievementFrameStartLandscape CGRectMake(-53.0f, 350.0f, 104.0f, 284.0f);
#define kGKAchievementFrameEndLandscape CGRectMake(20.0f, 350.0f, 104.0f, 284.0f);
所以不妨从Ray Wenderlich指南的Game Center代码着手,连同Type One Error通知代码,然后进行必要调整,所以我们最终的解决方案是:
1)呈现1个或更多成就通知。
2)以图像及完整标题和描述呈现通知。
3)以独立于iOS版本的形式呈现。
你认定玩家已完成某成就,不妨嵌入:
[GCHelper sharedInstance] reportAchievement:identifier
percentComplete:percentComplete];
或其他访问Game Center成就的方式。