[Cocos2D for iPhone]Xcode 4에 설치하고 간단한 프로젝트 만들어보기

2012/07/25 02:32


Cocos2D 로고



Cocos2D는 2D 게임엔진이다. 아이폰, 안드로이드, 윈도우등 다양한 환경에서 GPU기반으로 하는 고급 렌더링 게임을 만들고 싶을때 유용하게 사용할 수 있는 프레임워크중 하나이다. 


Xcode 4에 Cocos2D 설치 

Xcode 4에 설치하기 위해서 다음과 같은 절차가 필요하다. 

  1. http://www.cocos2d-iphone.org/wiki/doku.php/start 방문해 최신 안정한 압축파일 다운로드 받음. 현시점에서 최신버전이 2.0이다. 
  2. 압축을 푼다.
  3. 압축을 푼 폴더로 찾아가 ./install-templates.sh -f -u 로 설치
  4. Xcode 4를 사용해 설치 상태 확인. 아래와 같이 새 프로젝트를 실행할 때 나오면 성공!
    참고로 아래 3개 템플릿에서 첫번째는 Hello World를 찍어주는 예제이다. 두번째는 Box2d라는 2d물리엔진을 사용한 예제가 곁들인 거다. 세번째는 Chipmunk 물리엔진을 쓴것이다. 하나씩 만들어봐서 테스트 해보고 소스분석해보면 좋을 것 같다.  


Cocos2D 기본 프로젝트 만들기 

이제 Cocos2D 프로젝트를 만들어보자. 약 1~2년전 만에도 이렇게 쉽지 않았는데 프로젝트 템플릿이 너무 잘만들어져서 시작점이 꽤 쉬워진 편이다. 

  1. 위 사진에서 cocos2d iOS를 선택합니다. 그리고 Next!
  2. 프로젝트 명과 패키지를 입력합니다. 필요하다면 Device Family도 선택할 수 있겠죠?

  3. 코드를 한번 쭉 훑어봅시다. 아래와 같이 프로젝트 템플릿을 통해 프로젝트가 생성된다. Cocos2D는 완전 오픈소스였군요! 



  4. 실행합니다. 아래처럼 나오면 성공!



Cocos2D 기본 프로젝트 코드 분석해보기 

간단하게 코드를 분석해 보자! 가장 먼저 AppDelegate가 시작점이 겠으므로 application:didFinishLaunchingWithOptions: 코드를 보자. 주석을 보면 어떻게 만들어지는지 볼 수 있는데... 결국  UIViewController를 확장해서 만든 CCDirector를 생성하여 거기에 OpenGL화면을 만들어 자식으로 넣고 CCDirector 객체에 기본 설정을 지정한 다음 화면에 보일 수 있도록 UINavigationViewController를 사용해 window에 등재시킨다. 이 부분은 거의 공통사항이라 FPS표시 부분을 제외하고는 거의 그대로 써도 무방할 듯 하다. 중간에 RGB565, RGB555등의 용어는 모두 3D에 관련된 용어들이다. 인터넷 검색을 하면 의미를 알 수 있겠다.


- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
	// 메인 윈도우 생성 
	window_ = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];


    // RGB565 칼라 버퍼와 24비트 깊이 버퍼로 EAGView 를 생성한다.
	CCGLView *glView = [CCGLView viewWithFrame:[window_ bounds]
								   pixelFormat:kEAGLColorFormatRGB565	//RGBA8 칼라 버퍼kEAGLColorFormatRGBA8
								   depthFormat:0	//GL_DEPTH_COMPONENT24_OES, 24-비트 깊이 버퍼
							preserveBackbuffer:NO
									sharegroup:nil //쓰레드간 OpenGL 컨텐츠를 공유하기 위해
								 multiSampling:NO //멀티 샘플링하려면 YES
							   numberOfSamples:0 // 멀티 샘플링이 YES 일 때 1~4의 값을 설정
                        ];

    //디렉터 참조 (사실 디렉터는 UIViewController를 확장한 것이다.) 
	director_ = (CCDirectorIOS*) [CCDirector sharedDirector];

    //전체화면 
	director_.wantsFullScreenLayout = YES;

	// FSP와 SPF를 보여준다. 
	[director_ setDisplayStats:YES];

	// FPS 60으로 설정
	[director_ setAnimationInterval:1.0/60];

	// 디렉터에 생성한 OpenGL 뷰를 붙인다. 
	[director_ setView:glView];

	// 회전 및 다른 메시지 처리를 위해 델리게이트 지정 
	[director_ setDelegate:self];

	// 2D 투영 지정 
	[director_ setProjection:kCCDirectorProjection2D];
//	[director setProjection:kCCDirectorProjection3D];

	// iPhone4에서는 고해상도(레티나 디스플레이) 모드로 사용하고,
	// 다른 장치들은 저해상도를 유지시킨다
	if( ! [director_ enableRetinaDisplay:YES] )
		CCLOG(@"Retina Display Not supported");

	// 디폴트 텍스처 형식은 PNG/BMP/TIFF/JPEG/GIF 이미지용
	// 값은 RGBA8888, RGBA4444, RGB5_A1, RGB565를 사용.
	// 언제든지 값을 바꿀 수 있음
	[CCTexture2D setDefaultAlphaPixelFormat:kCCTexture2DPixelFormat_RGBA8888];

    // 접미어로 각 장비의 해상도 별로 이미지 로드를 정할 수 있도록 한다. 해당 접미어가 없으면 없는 접미어가 기본이 된다. 
	// iPad HD 에서 : "-ipadhd", "-ipad",  "-hd"
	// iPad 에서     : "-ipad", "-hd"
	// iPhone HD 에서 : "-hd"
	CCFileUtils *sharedFileUtils = [CCFileUtils sharedFileUtils];
	[sharedFileUtils setEnableFallbackSuffixes:NO];				// Default: NO. No fallback suffixes are going to be used
	[sharedFileUtils setiPhoneRetinaDisplaySuffix:@"-hd"];		// Default on iPhone RetinaDisplay is "-hd"
	[sharedFileUtils setiPadSuffix:@"-ipad"];					// Default on iPad is "ipad"
	[sharedFileUtils setiPadRetinaDisplaySuffix:@"-ipadhd"];	// Default on iPad RetinaDisplay is "-ipadhd"

	// PVR 이미지는 premultiplied alpha를 가진다고 가정함 
	[CCTexture2D PVRImagesHavePremultipliedAlpha:YES];

	// 스텍에 IntroLayer의 scene을 넣는다. 디렉터는 자동으로 보여질때 뷰가 실행될 것이다.
	[director_ pushScene: [IntroLayer scene]]; 

	
	// 네비게이션 뷰 컨트롤러를 만들고 그에 대한 루트를 디렉터로 한다.
	navController_ = [[UINavigationController alloc] initWithRootViewController:director_];
	navController_.navigationBarHidden = YES;
	
	// 네비게이션 뷰 컨트롤러를 루트 뷰 컨트롤로로 만듬 
//	[window_ addSubview:navController_.view];	// Generates flicker.
	[window_ setRootViewController:navController_];
	
	// 메인 윈도우를 보이게 함 
	[window_ makeKeyAndVisible];
	
	return YES;
}


중간에 [director_ pushScene: [IntroLayer scene]];가 실질적인 2D 컨텐츠가 보여지는 영역으로 Scene를 만들고 거기에 Layer를 등록하는 형태이다. IntroLayer는 단지 초반에 Cocos2D 런칭이미지로 부터 HelloWorldLayer로 넘어가기 위한 교두보일 뿐이다. 실제 구현은 HelloWorldLayer에 있다고 보면 되겠다. 


라이프 사이클을 처리하기 위해 생성한 director를 호출하도록 만들어져 있는 것도 확인하자. 

// getting a call, pause the game
-(void) applicationWillResignActive:(UIApplication *)application
{
	if( [navController_ visibleViewController] == director_ )
		[director_ pause];
}

// call got rejected
-(void) applicationDidBecomeActive:(UIApplication *)application
{
	if( [navController_ visibleViewController] == director_ )
		[director_ resume];
}

-(void) applicationDidEnterBackground:(UIApplication*)application
{
	if( [navController_ visibleViewController] == director_ )
		[director_ stopAnimation];
}

-(void) applicationWillEnterForeground:(UIApplication*)application
{
	if( [navController_ visibleViewController] == director_ )
		[director_ startAnimation];
}

// application will be killed
- (void)applicationWillTerminate:(UIApplication *)application
{
	CC_DIRECTOR_END();
}

// purge memory
- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application
{
	[[CCDirector sharedDirector] purgeCachedData];
}

// next delta time will be zero
-(void) applicationSignificantTimeChange:(UIApplication *)application
{
	[[CCDirector sharedDirector] setNextDeltaTimeZero:YES];
}


IntroLayer는 CCLayer를 확장한 것으로 정적함수로 CCScene의 참조를 반환하도록 구현하고 있다. 이 형태는 HelloWorldLayer와 같다. 

+(CCScene *) scene { // 'scene' 는 autorelease 객체이다. CCScene *scene = [CCScene node]; // 'layer'는 autorelease 객체이다. 자신을 생성한다. IntroLayer *layer = [IntroLayer node]; // scene에 layer를 자식으로 추가한다. [scene addChild: layer]; // scene를 반환한다. return scene; }

IntroLayer에 onEnter는 처음 자동실행되는 함수이다. 여기에 메인화면을 붙이고 1초이후에 Transition을 실행하도록 스케줄링을 하고 있다. 결국 이 화면은 코코스2D 화면이 뜬다. 


-(void) onEnter
{
	[super onEnter];

	// 디렉터로부터 윈도우 크기를 알아온다.
	CGSize size = [[CCDirector sharedDirector] winSize];

	CCSprite *background;
	
	//아이폰인 경우에는 Defualt.png를 가져와 CCSprite 객체를 만든다. 
	//아이폰이 아닌경우에는 iPad이므로 iPad용 이미지를 가져와 CCSprite 객체를 만든다.
	if( UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone ) {
		background = [CCSprite spriteWithFile:@"Default.png"];
		background.rotation = 90;
	} else {
		background = [CCSprite spriteWithFile:@"Default-Landscape~ipad.png"];
	}
	//화면중앙에 위치시킨다. CCSprite는 좌측상단이 중심이 아니라 항상 객체의 중심이 된다. 
	background.position = ccp(size.width/2, size.height/2);

	// 이 레이어에 자식으로 생성한 CCSprite객체를 추가한다.
	[self addChild: background];
	
	// 1초후에 새로운 scene를 추가하기 위해 transition을 실행한다. makeTransition:이 그것을 담당한다.
	[self scheduleOnce:@selector(makeTransition:) delay:1];
}


makeTransition: 함수를 잠깐 살펴보자. 디렉터에는 replaceScene라는 함수가 있는데 여기에 직접 [HelloWorldLayer scene]를 넣지 않고 CCTransitionFade에 정의된 정적 함수를 호출해 Fade효과를 준다음에 scene를 교체하도록 했다. 1초동안 흰색으로 Fade되었다가 scene로 교체된다. Cocos2d 개발자가 이런 인터페이스도 있다라는 것을 예제코드에 넣어준 셈이다. 

-(void) makeTransition:(ccTime)dt { [[CCDirector sharedDirector] replaceScene:[CCTransitionFade transitionWithDuration:1.0 scene:[HelloWorldLayer scene] withColor:ccWHITE]]; }


이제 마지막으로 HelloWorldLayer를 보자. 사실 분석을 할 필요도 없을 정도로 그냥 레이블과 메뉴를 붙여보는 수준이다. 하지만 시작점으로 이렇게 객체를 생성해서 붙일 수 있다라는 것을 설명해주는 좋은 예제인데다가 GameKit를 사용해 2D 게임엔진에 맞게 필요한 아카이브 정보와 리더보드 정보를 붙이는 예제까지 곁들였다. 


-(id) init
{
	if( (self=[super init]) ) {
		
		// 레이블 객체를 생성하고 초기화 한다. Hello World를 만들고 폰트는 Marker Felt를 사용한다. 사이즈는 64로 했네.
		CCLabelTTF *label = [CCLabelTTF labelWithString:@"Hello World" fontName:@"Marker Felt" fontSize:64];

		// 디렉터로부터 윈도우 사이즈를 얻는다.
		CGSize size = [[CCDirector sharedDirector] winSize];
	
		// 레이블을 화면에 중심에 배치시킨다.
		label.position =  ccp( size.width /2 , size.height/2 );
		
		// 레이블을 이 레이어에 자식으로 추가한다.
		[self addChild: label];
		
		
		
		//
		// 리더보드와 아카이브
		//
		
		// 메뉴의 폰트 기본 사이즈는 28로 설정 
		[CCMenuItemFont setFontSize:28];
		
		// 아카이브 메뉴 아이템 생성. 블록을 사용해 이 메뉴 아이템을 터치했을 때 처리  
		CCMenuItem *itemAchievement = [CCMenuItemFont itemWithString:@"Achievements" block:^(id sender) {
			
			
			GKAchievementViewController *achivementViewController = [[GKAchievementViewController alloc] init];
			achivementViewController.achievementDelegate = self;
			
			AppController *app = (AppController*) [[UIApplication sharedApplication] delegate];
			
			[[app navController] presentModalViewController:achivementViewController animated:YES];
			
			[achivementViewController release];
		}
									   ];

		// 리더보드 메뉴 아이템 생성. 블록으로 이 아이템을 터치했을 때 처리 
		CCMenuItem *itemLeaderboard = [CCMenuItemFont itemWithString:@"Leaderboard" block:^(id sender) {
			
			
			GKLeaderboardViewController *leaderboardViewController = [[GKLeaderboardViewController alloc] init];
			leaderboardViewController.leaderboardDelegate = self;
			
			AppController *app = (AppController*) [[UIApplication sharedApplication] delegate];
			
			[[app navController] presentModalViewController:leaderboardViewController animated:YES];
			
			[leaderboardViewController release];
		}
									   ];
		//생성한 메뉴 아이템을 기반으로 메뉴 생성
		CCMenu *menu = [CCMenu menuWithItems:itemAchievement, itemLeaderboard, nil];
		
		//메뉴 아이템을 20을 떨어뜨려 수평으로 배치 
		[menu alignItemsHorizontallyWithPadding:20];

		//메뉴를 중간에서 아래로 50 떨어진 곳에 배치 
		[menu setPosition:ccp( size.width/2, size.height/2 - 50)];
		
		// 레이어에 메뉴을 자식으로 추가 
		[self addChild:menu];


} return self; }

이것으로 Cocos2D for iPhone의 설치방법 및 프로젝트 생성방법, 마지막으로 가장 간단한 HelloWorld 예제까지 살펴보면서 Cocos2D를 이해해 볼 수 있었다. 나머지 2개의 프로젝트 템플릿으로 직접 생성해서 물리엔진을 사용하는 방법까지 함께 보면 기초중에 기초는 학습했다고 봐도 되겠다. 


Chipmunk 물리엔진을 활용한 예제 



Box2D 물리엔진 활용 예제 



참고 링크 

Cocos2D for iPhone 공식페이지 : http://www.cocos2d-iphone.org

Cocos2D for iPhone 프로그래밍 가이드 : http://www.cocos2d-iphone.org/wiki/doku.php/prog_guide:index 


글쓴이 : 지돌스타(http://blog.jidolstar.com/830)

저작자 표시 비영리 동일 조건 변경 허락

iOS , , , , , , , , , , ,

  1. Blog Icon
    Mond

    아주 많은 도움이 되고 있습니다.ㅎㅎ
    혹시 appdelegate 의 preservebackbuffer 와 sharegroup 부분 자세히 설명해 주실 수 있을까요..ㅠ 구글링을 해봐도 잘 안나오고
    한번 궁금한건 끝까지 가는 성격이라 정확히 무엇을 의미하는지 궁금하네요.