http://lomohome.com/357 mokorean@gmail.com 어플에 GameCenter 를붙이자! (+ 겜센터스타일의알림창 Notification 도붙이자!) - 개인적인용도로요약한글이라글에서는경어체를사용하지않습니다. 양해부탁드립니다. - 회사에서진행하고있는프로젝트와관련이있어과도한모자이크가있습니다. 양해부탁드립니다. ios 4.1 부터지원하기시작한 Apple 의 GameCenter 를내어플에붙여보는작업을해보자. GameCenter 의가이드가잘되어있으니전체적인개발방법은가이드를참고해보고이번포스팅에서는속성으로필요한부분만정리해서올려본다. 간단히 GameCenter 는지원하는어플의세계랭킹, 도전목표, 같이게임을하는친구목록등을지원하고또한 Auto-Match ( 대전상대매치 ), 음성채팅같은 API 도제공된다. ( 이전에 Apple 이지원하기전에는 OpenFeint 등이유명한솔루션이었다 ) - 참고 : Apple 의 GameCenter Developer guide http://developer.apple.com/library/ios/#documentation/networkinginternet/conceptual/gamekit_guide/ GameCenterOverview/GameCenterOverview.html 1. 사전작업먼저어플이 itunes connect 에등록이되어있어야한다. (https://itunesconnect.apple.com) 개발자계정을입력후로그인하면 Manage Your Applications 라는메뉴를누른다. 그다음화면에서 GameCenter 를적용할어플을클릭한다.
그다음 Manage Game Center 를눌러서게임센터관리로들어간다. 여기서 Game Center 를 Enable 시켜준다. 이미테스트용도로 Enable 시켰기때문에화면에서는 Disable 로표시된다. Leaderboard 는간단히말해점수판이다. 전세계사용자들과나자신의점수를비교해볼수도있고 GameCenter 에친구들이같은어플 ( 게임 ) 을사용한다면친구들간의순위도제공된다. 먼저점수판을하나셋팅해본다. Edit 를누른뒤 Add Leaderboard 버튼으로점수판을하나생성한다. 테스트용도이므로 Single Leaderboard 로생성을했다. Leaderboard Reference Name 은내가알아볼만한이름으로셋팅하면되고 Leaderboard ID 가중요한데프로그램에서참조되는값이므로유니크한이름으로셋팅해야된다. Sort Order 는오름차순, 내림차순정렬등을선택하고 Add Language 버튼으로언어별표시되는이름뒤에붙는점수표시법등을설정할수있다.
그다음다시 Manage 화면으로와서이번엔게임목표 (Achievements) 를설정해본다. 목표는어플당 1000 점한도내에서목표 1 개당 1~100 점이내로여러개를설정할수있다. Add New Achievement 버튼으로새로운목표를하나만들어본다. Achievement Reference Name 은 itunes Connect 에서관리하게편하게알아볼만한이름으로설정한다. Achievement ID 는마찬가지로프로그램에서참조할이름을적어준다. Hidden 은공개된목표인지, 숨겨진목표인지설정하고 Point Value 로목표를완수했을때주어지는점수를셋팅한다. 100 점까지셋팅이가능하다. Add Language 버튼으로언어별로표시될이름, 목표완수전에표시될설명, 완수후에표시될설명, 그리고목표에해당하는아이콘이미지를넣어준다. 테스트로몇개만들어보고이상으로 itunes Connect 사이트에서설정할사전작업은완료되었다.
2. 코드적용 2.1. 라이브러리추가 xcode 를열고즐거운코딩작업을시작한다. 먼저 GameKit 라이브러리가프로젝트에포함이되어야한다. xcode 4 로넘어오면서이게어디있나한참찾았는데 xcode 4 에서는다음에서필요한라이브러리를포함시킬수있다. 프로젝트파일을선택하고 Targets 에서선택하고 Build Phases 를누른후 Link Binary with Libraries 에서 GameKit.framework 를추가해준다. 그리고게임센터에서점수를기록하거나목표를달성했을때게임센터스타일의노티를붙여주기위해 typeoneerror 블로그의 GKAchievementNotification 소스를추가로붙이기위해서, 다운받은 ( 링크는아래에... 그리고블로그에도첨부파일로 ) 소스와이미지들을프로젝트에추가해준다. ( 여기에선 typeoneerror-gkachievementnotification-8a90404.zip 사용 ) http://www.typeoneerror.com/articles/post/game-center-achievement-notification 겜센터스타일의노티가기본적으로뜰때풀사이즈의어플을기준으로했기때문에내가작업하고있는어플에서보면노티가나오다가짤려보인다. 문제는 20 픽셀을잡고있는스테이더스바때문인데스테이더스바의길이만큼더해서노티가더내려오도록수정을했다. 다음수정은상단에스테이더스바가있는어플일때만해주면된다. ( 자신의어플에맞게 Customize 해서쓰도록하자 ) 다운받은소스의 GKAchievementNotification.h 의파일을보면다음과같은정의구문이있는데기본 10 픽셀만큼내려오는걸 30 필셀만큼내려오도록수정한다. #define kgkachievementframeend 여기서 10.0f 를 #define kgkachievementframeend 이렇게 30.0f 로. (20픽셀만큼더함 ) CGRectMake(18.0f, 10.0f, 284.0f, 52.0f); CGRectMake(18.0f, 30.0f, 284.0f, 52.0f);
2.2. 게임센터접속메소드구현 게임센터를접속시켜야하는데 MainView 쪽에작업해도되지만나는어플안에서마구가져다쓸수있는인스턴스클래스에접속, 점수보내는등의메소드를구현해놨다. 인스턴스클래스 AppUtils.h #import <GameKit/GameKit.h> #import "GKAchievementHandler.h" // 이건노티를위해서임포트 @interface AppUtils : NSObject {! ~~~~ ~~~~ /////////////////Geunwon,Mo : GameCenter 추가 start ///////////// + (BOOL) isgamecenteravailable ; // 게임센터가사용가능하지알아보는메소드 + (void) connectgamecenter; // 게임센터에접속하는메소드 +(void) sendscoretogamecenter:(int)_score; // 게임센터서버에점수보내는메소드 + (void) sendachievementwithidentifier: (NSString*) identifier percentcomplete: (float) percent; // 게임센터서버에목표달성보내는메소드 + (void) resetachievements; // 테스트용으로목표달성도를리셋하는메소드 /////////////////Geunwon,Mo : GameCenter 추가 end ///////////// @end AppUtils.m ~~~( 생략 ) /////////////////Geunwon,Mo : GameCenter 추가 start ///////////// //GameCenter 사용가능단말인지확인 + (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); //GameCenter 로그인 + (void) connectgamecenter{ NSLog(@"connect... to gamecenter"); if([gklocalplayer localplayer].authenticated == NO) { // 게임센터로그인이아직일때 [[GKLocalPlayer localplayer] authenticatewithcompletionhandler:^(nserror* error){ if(error == NULL){ NSLog(@" 게임센터로그인성공 ~"); else { NSLog(@" 게임센터로그인에러. 별다른처리는하지않는다."); ]; - 계속
// 게임센터서버로점수를보낸다. +(void) sendscoretogamecenter:(int)_score{ GKScore* score = [[[GKScore alloc] initwithcategory:@"kpoint"]autorelease]; // 위에서 kpoint 가게임센터에서설정한 Leaderboard ID score.value = _score; // 아래는겜센터스타일의노티를보여준다. 첫번째가타이틀, 두번째가표시할메세지 [[GKAchievementHandler defaulthandler] notifyachievementtitle:@"nbank Point!" andmessage:[nsstring stringwithformat:@"nbank Point %d 점을기록하셨습니다.",_score]]; // 실지로게임센터서버에점수를보낸다. [score reportscorewithcompletionhandler:^(nserror* error){ if(error!= NULL){ // Retain the score object and try again later (not shown). ]; // 게임센터서버로목표달성도를보낸다. 첫번째가목표 ID, 두번째가달성도. 100% 면목표달성임 + (void) sendachievementwithidentifier: (NSString*) identifier percentcomplete: (float) percent{ NSLog(@"-- 겜센터 : sendachievementwithidentifier %@, %f",identifier,percent); GKAchievement *achievement = [[[GKAchievement alloc] initwithidentifier: identifier] autorelease]; if (achievement) { achievement.percentcomplete = percent; [achievement reportachievementwithcompletionhandler:^(nserror *error) { if (error!= nil) { ]; // 이아래는게임센터로부터목표달성이등록되면실행되는리스너 (?) [GKAchievementDescription loadachievementdescriptionswithcompletionhandler: ^(NSArray *descriptions, NSError *error) { if (error!= nil){ // process the errors if (descriptions!= nil){ // 목표달성이등록되면노티로알려준다. for (GKAchievementDescription *achievementdescription in descriptions){ if ([[achievementdescription identifier] isequaltostring:identifier]){ // 보낸 ID와일치하면달성도에따라노티를보여준다. if (percent >= 100.0f) { // 100% 면달성완료노티를... [[GKAchievementHandler defaulthandler] notifyachievement:achievementdescription]; else { // 100% 가안되면진행도를노티. [[GKAchievementHandler defaulthandler] notifyachievementtitle:achievementdescription.title andmessage:[nsstring stringwithformat:@"%.0f%% 완료하셨습니다.",percent]]; ]; - 계속
// 테스트할때현재까지모든진행도를리셋하는메소드. + (void) resetachievements { // Clear all progress saved on Game Center [GKAchievement resetachievementswithcompletionhandler:^(nserror *error) { if (error!= nil){ // handle errors ]; /////////////////Geunwon,Mo : GameCenter 추가 end ///////////// 이제어플을실행하고메인뷰컨트롤러의 viewdidload 메소드에게임센터접속을코딩한다. 이프로그램에서는 MainMenuViewController.m 에다가코딩해놨다. #import "AppUtils.h" ~~~~~( 생략 ) - (void)viewdidload { ~~~~~( 생략 ) /////////////////Geunwon,Mo : GameCenter 추가 start ///////////// //AppUtils 가인스턴스메소드이기때문에걍쓴다 if ([AppUtils isgamecenteravailable]) { // 게임센터가가능한단말이면... [AppUtils connectgamecenter]; // 게임센터접속 ~ /////////////////Geunwon,Mo : GameCenter 추가 end ///////////// ~~~~~( 생략 ) 이제게임센터에접속하고, 점수를보여줄준비는끝났다. 프로그램을실행해보면다음과같이게임센터에접속하는모습을볼수있다.
2.3. 게임센터로점수와목표달성도를보내보자 이제자신의프로그램플로우에따라게임센터서버로점수와목표달성도를보내보는메소드를구현해보자. 사실보내는메소드는위에구현해놨기때문에테스트메소드로사용법만을적어본다. 프로그램에서적당한위치에 ( 실제로게임센터로데이터를보내야하는클래스에서 ) 테스트메소드들을만들었다. // 테스트메소드들 - (IBAction)test1:(id)sender { // 이렇게보내면 er10 이라는 ID 를가지는목표달성도가 25% 가찍히게된다. [AppUtils sendachievementwithidentifier:@"er10" percentcomplete:25.0f]; - (IBAction)test2:(id)sender { // 이렇게보내면 er10 이라는 ID 를가지는목표달성도가완료되게된다. [AppUtils sendachievementwithidentifier:@"er10" percentcomplete:100.0f]; - (IBAction)test3:(id)sender { // 이렇게보내면 sit 이라는 ID 를가지는목표달성도가완료되게된다. [AppUtils sendachievementwithidentifier:@"sit" percentcomplete:100.0f]; - (IBAction)testpoint:(id)sender { int r = rand() % 1000; // 이렇게보내면점수판에 1000 사이의정수가랜덤으로기록되게된다. [AppUtils sendscoretogamecenter:r]; // 이렇게보내면목표달성도가리셋되게된다. [AppUtils resetachievements];
2.4. 점수판도띄워보고목표달성판도띄워보자! 메뉴또는 About 화면등.. 원하는위치에버튼을만들고누르면게임센터의점수판과목표달성판이나오도록해보자. 나는 AppInfoViewController 라는클래스에코딩을해놨다. 포인트순위표, 목표달성이란버튼을만들고각각 Touch Up Inside 이벤트에 openleaderbd 라는점수판을띄우는메소드와 openarchivementbd 라는목표달성판을띄우는메소드를만들었다. (Archivement 는오타인데만들고나서나중에수정하기귀찮아서그냥사용 -_-) AppInfoViewController.h #import <GameKit/GameKit.h> @interface AppInfoViewController : UIViewController <GKLeaderboardViewControllerDelegate, GKAchievementViewControllerDelegate>{ // 점수판, 목표달성판을띄우는뷰컨트롤러딜리게이트구현 /////////////////Geunwon,Mo : GameCenter 추가 start - (IBAction)openLeaderBD:(id)sender; // 점수판을띄운다 - (IBAction)openArchivementBD:(id)sender; // 목표달성판을띄운다 - (void) showleaderboard; // 실제로점수판을띄우는부분구현메소드 - (void) leaderboardviewcontrollerdidfinish:(gkleaderboardviewcontroller *) viewcontroller; // 점수판이닫힐때호출되는메소드 - (void) showarchboard; // 목표달성판을띄우는부분구현메소드 - (void)achievementviewcontrollerdidfinish:(gkachievementviewcontroller *) viewcontroller; // 목표달성판이닫힐때호출되는메소드 /////////////////Geunwon,Mo : GameCenter 추가 end @end
AppInfoViewController.m ~~~( 생략 ) /////////////////Geunwon,Mo : GameCenter 추가 start ///////////// ///////////////// 점수판 // 점수판버튼이눌리면호출된다. - (IBAction)openLeaderBD:(id)sender{ NSLog(@"open leader board"); [self showleaderboard]; // 실행 ~ - (void) showleaderboard { GKLeaderboardViewController *leaderboardcontroller = [[[GKLeaderboardViewController alloc] init]autorelease]; if (leaderboardcontroller!= nil) { // 레더보드델리게이트는나임 leaderboardcontroller.leaderboarddelegate = self; // 레더보드를현재뷰에모달로띄운다. [self presentmodalviewcontroller:leaderboardcontroller animated: YES]; // 레더보드델리게이트를구현한부분. 닫힐때호출된다. - (void) leaderboardviewcontrollerdidfinish:(gkleaderboardviewcontroller *) viewcontroller { [self dismissmodalviewcontrolleranimated:yes]; // 점수판모달뷰를내림 // 추가적으로자신의어플에맞게구현해야할것이있으면한다. ///////////////// 목표달성. ( 점수판구현과방법은똑같음 ) // 목표달성판버튼이눌리면호출된다. - (IBAction)openArchivementBD:(id)sender { NSLog(@"open archivement board"); [self showarchboard]; - (void) showarchboard { GKAchievementViewController *archivecontroller = [[[GKAchievementViewController alloc] init] autorelease]; if (archivecontroller!= nil) { archivecontroller.achievementdelegate = self; [self presentmodalviewcontroller:archivecontroller animated: YES]; - (void)achievementviewcontrollerdidfinish:(gkachievementviewcontroller *) viewcontroller{ [self dismissmodalviewcontrolleranimated:yes]; ////////////////////Geunwon,Mo : GameCenter 추가끝 ////////////// 따로주의해야할점은점수판과목표달성판은 UIView 위에띄워주게되어있는데지금작업한어플은 UIView 에서도는어플이라상관없지만 cocos2d 나기타 opengles 등을이용한어플이라면 UIView 를하나띄워주고그뷰의모달로띄워주어야화면에표시가될것이다. ( 해보지는않았음 -_- 구글링추천 )
이제 누르면 다음과 같이 점수판과 목표달성판이 이쁘게 뜬다. 끗. 2011.4.19 모근원 (Geunwon,Mo) mokorean@gmail.com twitter : @mokorean http://lomohome.com