얼마전 잘 사용하던 8400gs를 잠시 뽑아두고, 그 동안 미개봉 상태로 짱박아두었던, GT220 hdmi 를 꽂아서, 윈도우7으로 게임을 잘하고 있었다.

그런데, 맥으로 부팅을 하니!!! 그동안 잘 나오던 사운드가 잘 나오지를 않네????

그래서 VoodooHDA를 확인하고, 사운드 설정을 확인 하니, nVidia의 HDMI를 사용하도록 되어 있었다. 휴...

바로 voodoohda.googlecode.com에서 소스를 댕겨서 확인에 들어가보니...
사용자가 오디오 디바이스를 선택하도록 해놓지 않았네.  IOPCIPrimaryMatch이런걸 쓰면 된다고는 되어 있으나, audio probe 과정을 보니, 처음 올라온놈만 살리게 되어 있었다. 그리고 더군다나.. 32비트로 컴퐐해야 잘 돌아가고 있는 코드들...

다운 받고, 64비트 전용으로 빌드를 하니, 에러가 181개인가 발생하는 걸 다 수정했다. 휴~ 오랜만에 몰입 했네.
그리고, 순전히 나를 위해서 nVidiia HDMI는 설정하지 않도록 수정해서 드라이버 올리고 부팅하니..


두둥.~~

지금 음악 듣고 있다. 64비트 커널에, 완전히 64비트 드라이버를 써야 제맛.

배포되는 64비트들은 에뮬되는 버전인데. 지금 고친 코드는 완전히 64비트를 온전히 사용하게 수정한거라서 또한 마음이 좋다.

혹시 몰라서 첨부해두니, 해킨토시를 사용하는 사람중에서 VoodooHDA를 사용하는 사람들중에서, nVidia의 HDMI때문에 사운드를 잡지 못하는 사람들은 첨부 VoodooHDA 바이너리를 받아다가, 설치해서 사용하면 된다.

설치 방법은 기존 VoodooHDA 최신 패키지를 설치한 상태를 가정하고 아래와 같이 하면 된다.(이 설치 법을 모른다면, 답글 달아주면 설명 추가하겠음)

1. 첨부 VoodooHDA 를 다운 받는다.
2. 터미널을 열고 아래의 명령을 입력한다. 다운로드한 곳에서 해야 함.
      - sudo cp -R VoodooHDA /System/Library/Extensions/VoodooHDA.kext/Contents/MacOS/
      - sudo chmod -R 755   /System/Library/Extensions/VoodooHDA.kext
      - sudo chown -R root:wheel/System/Library/Extensions/VoodooHDA.kext
3. 재부팅한다.

위의 방법은 기존 VoodooHDA를 이용하여, 오디오를 잡는 데 성공한 사람들을 위한 내용이다.
위의 방법으로 실패할경우, VoodooHDA 패키지를 다시 설치해주고, 일단 이글에 답글을 달면 코드를 또 수정하는 일이 있어도 한번 확인해보겠다.(필요한 정보는 메인보드에 달려있는 사운드 카드 정보와 사용중인 오디오 관련된 장치들 정보이다. 예를 들면  HDMI같은것들)
 
빌드 정보는, 10.6을 위한 드라이버이고, 오직 64비트만 지원한다. 32비트가 필요한 사람은 따로 답글을 달아주면 빌드 해서 올림. 

'코딩하고 > iOS' 카테고리의 다른 글

iOS용 게임 개발기 -7-  (0) 2011.08.19
iOS용 게임 개발기 -6-  (0) 2011.08.17
iOS용 게임 개발기 -5-  (0) 2011.08.10
iOS용 게임 개발기 -4.1-  (0) 2011.08.02
iOS용 게임 개발기 -4-  (0) 2011.08.01
블로그 이미지

커뉴

이 세상에서 꿈 이상으로 확실한 것을, 인간은 가지고 있는 것일까?

,
오늘은 sprite에 대해서 이야기 해보자.
sprite는 우리가 게임을 만들때,(2d게임) 반드시 사용하게 되어 있는 이미지들을 말한다.

iOS용 앱에서는 주로 png 파일을 많이 사용하는데, cocos2d에서는 개발자가 따로 처리를 하지 않아도, 이미지들을 쉽게 콘트롤하고 가지고 놀수 있게 많은 api들을 제공하고 있다.  

4.1에서 만들었던, 정말 간단한(?) 시계에 이제는 이미지를 넣고, 약간의 효과를 줘보자.!!!
시계 이미지의 배경은 바로, 본인이 개발했던 BlueOcean게임의 배경들을 일정한 시간을 두고 FadeIn/Out 효과를 주고 바뀌도록 하는 것으로 한번 만들어 보겠다. 

이번에도 역시 두개의 파일만 수정하면 된다.  

배경이미지들을 이 예제에서는 3개룰 사용하여 정해진 시간이 되면, 배경이미지를 교체해주도록 하기위해서 아래 굵게 표시된 부분처럼, 인덱스하는 정수형 변수 하나(나중에 배열의 인덱서로 사용된다.), 배경이미지들을 관리할수 있도록 배열을 하나 선언한다.
 

//

//  HelloWorldLayer.h

//  

//



// When you import this file, you import all the cocos2d classes

#import "cocos2d.h"


// HelloWorldLayer

@interface HelloWorldLayer : CCLayer

{

    CCLabelTTF *label;

    

    int             _currentBg;     // 배경화면 이미지가 무엇인지 확인하기 위한 인덱스.

    NSMutableArray* _bgSpriteList;  // 배경화면 이미지들을 저장할 배열.

}


// returns a CCScene that contains the HelloWorldLayer as the only child

+(CCScene *) scene;


@end


 
objective-C 언어는 C언어의 문법을 그대로 사용할수 있다. 위에서 보는 바와 같이 int 형 변수를 선언하는 것도, C와 똑같이 하면 된다. 
NSMutableArray 는 정적 배열이 아닌(처음부터 그 크기가 정해진 배열) 동적 배열이다, 자바의 ArrayList와 비슷하다고 생각하면 된다. 
아래 소스에서 확인할수 있겠지만, 생성후 필요할때 오브젝트들을 마음대로 추가해주고 꺼내 쓸수 있다. 그리고 그 오브젝트들을 지우는 것도 간단하게 할수 있다.



원래 시간을 찍어주던 부분에서, 배경 이미지들을 생성해서 배열에 넣어주고, 스케쥴러를 이용해서, 4초마다 이미지들을 빠꿔주게 하는 부분이 추가 되었다.아래 굵은 부분만 수정되고 추가된 부분이다. 해당 주석들을 참고하면 어떤것인지 바로 이해할수 있다.

//

//  HelloWorldLayer.m

//   

-(void)bgControl

{

   

    CCSprite *sprite = (CCSprite *)[_bgSpriteList objectAtIndex:_currentBg];  // 배열에서 이미지를 하나 꺼내온다.

    

    id action1 = [CCFadeIn actionWithDuration:2.0f];    // FadeIn Effect를 2초동안에 걸쳐 동작하게 함.

    id action2 = [CCFadeOut actionWithDuration:2.0f];  // FadeOut Effect를 2초동안에 걸쳐 동작허게 함.

    [sprite runAction:[CCSequence actions:action1, action2,nil]]; // FadeIn -> FadeOut순서로 효과가 동작되게 지정함.   

    _currentBg++; // 다음이미지를 불러올수 있게 인덱서를 증가 시켜줌.

    if(_currentBg==3) // 이미지는 3개 밖에 없으므로 다시 0으로 초기화 해준다.

        _currentBg=0;

}

-(id) init

{

// always call "super" init

// Apple recommends to re-assign "self" with the "super" return value

if( (self=[super init])) {

// create and initialize a Label

label = [CCLabelTTF labelWithString:@"Hello World" fontName:@"AppleGothic" fontSize:32];


// ask director the the window size

CGSize size = [[CCDirector sharedDirector] winSize];

// position the label on the center of the screen

label.position =  ccp( size.width /2 , size.height/4 );

// add the label as a child to this Layer

[self addChild: label z:2 tag:2];

        

                [self schedule:@selector(updateTime) interval:1];

        

        

                _bgSpriteList = [[NSMutableArray alloc] init];  // 배열 생성.

        
                // 루프를 돌면서, 이미지들을 생성하고, 배열에 넣는다. 

                for(int i=0;i<3;i++)

                {

                     CCSprite *sprite=
                            [
CCSprite spriteWithFile:[NSString stringWithFormat: @"scenario%02d.png",i]];

            

            

                     [_bgSpriteList addObject:sprite]; // 배열에 추가.


            

                     sprite.anchorPoint = CGPointZero;// 해당 이미지의 기준이 되는 점을 정해줌. 이후 포지션등을 지정할때 기준이 됨.                        

                     sprite.opacity=0; //FadeIn Effect를 사용할것이므로, 이미지가 보이지 않게 한다. 

                     [sprite setPosition: ccp(0, 0)];  // 위에서 anchorPoint를 0,0으로 정의하고, 여기서 이미지의 위치를 0,0으로

                                                              // 정의했으므로,  이미지는 화면의 0,0좌표에 이미지의 0,0좌표를 맞게 설정한다.

                     [self addChild:sprite z:1 tag:1]; // layer에 sprite를 추가해줌.(이부분이 없으면 아무것도 안된다.

                }

                _currentBg=0; 

                [self bgControl];


                [self schedule:@selector(bgControl) interval:4]; // 배경이미지를 효과를 주고 교체해줌.

}

return self;

}


// on "dealloc" you need to release all your retained objects

- (void) dealloc

{

// in case you have something to dealloc, do it in this method

// in this particular example nothing needs to be released.

// cocos2d will automatically release all the children (Label)

          [self unschedule:@selector(updateTime)];   // 스케쥴러 해제

        [self unschedule:@selector(bgControl)];     // 스케쥴러 해제

        [_bgSpriteList release];  // 배열 해제

        _bgSpriteList=nil;

    

// don't forget to call "super dealloc"

[super dealloc];

}

 


백문이 불여일견이다. 어떻게 동작하는지 아래 동영상을 보자.

 

사실 구현을 위해서 정말 진짜!!! 진짜!! 기본적인 내용들로만 구현했지만, 위의 코드들 이용해서 이미지들을 수백개정도를 관리하도록(이때는 파일명만 리스토에 넣고 그때 그때 sprite를 생성하돌고 해야 메모리 부족이 생기지 않는다.) 하고, 단순하게 4초 마다가 아니라, 특정 시간이 변하거나,할때마다 이미지들을 교체하게 해주면, 정말 그럴사한 슬라이드 어플이 될수 있다.  생각보다 효과 넣는것도 쉽고, 코드만들기도 쉬우므로, 다른 이펙트들을 찾아서 한번 응용해보는것도 좋다.

다음 포스트에서 Effect들을 더 많이 알아보도록 하겠다.
 

'코딩하고 > iOS' 카테고리의 다른 글

iOS용 게임 개발기 -6-  (0) 2011.08.17
VoodooHDA 64비트 빌드 그리고, nVidia HDMI 제거.  (2) 2011.08.15
iOS용 게임 개발기 -4.1-  (0) 2011.08.02
iOS용 게임 개발기 -4-  (0) 2011.08.01
iOS용 게임 개발기 -3.1-  (0) 2011.07.11
블로그 이미지

커뉴

이 세상에서 꿈 이상으로 확실한 것을, 인간은 가지고 있는 것일까?

,
오늘 포스트는, 어제 잠시 보았던 cocos2d소스를 정말 최소한 수정하여, 정말 간단한 시계어플(?)을 만드는 것이다.
사실 말이 시계 어플이지, 아무런 UI도 없다. 사실 시계는 우리에게 시간을 알려주는것이 목적이므로, 그 기본에 정말 충실한 어플이다.

HelloWorld 어플에서 수정해야 하는 부분은 HelloWorldLayer.h와 m 파일이다.

시간을 찍어주고, 저장하고 있을 label을 멤버로 올리고(기존 "HelloWorld"를 저장하던 부분), 스케쥴러를 1초마다 동작하게 하여, 시간을 다시 업데이트 해주는 함수를 추가한다. 이게 끝이다. 이러면 시계가 된다. 앱스토어에 존재하는 수만은 시계 어플들은 여기서 시작한다, 여기다가 배경 사진 그럴사한거 넣어주고, 폰트도 이쁜놈으로 넣어주고, 배치를 그럴사하게 해주면.. 앱스토에 올려놓고 팔거나, 무료로 배포할수 있는 것이다. 이 모든걸 1시간도 안걸려서 만들수 있다. 이후 sprite를 이야기 하고 나서, 이 시계 어플에 배경을 넣고 좀 꾸며 보기로 하자.

바로 소스를 보자.
 

//

//  HelloWorldLayer.h

//  

//



// When you import this file, you import all the cocos2d classes

#import "cocos2d.h"


// HelloWorldLayer

@interface HelloWorldLayer : CCLayer

{

    CCLabelTTF *label; // --> 이걸 추가했다. 아래 프로퍼티 같은건 선언하지 않았다. 기능 구현에만 충실하자.!!!!

}


// returns a CCScene that contains the HelloWorldLayer as the only child

+(CCScene *) scene;


@end


 


 

//

//  HelloWorldLayer.m

//  

 
// 추가된 함수. 매초마다 호출되어 시간을 찍어준다. 아래 코드들은 시간을 찍거나 사용하는 어플에서는 공통으로 사용할수 있는 코드이다. 

- (void) updateTime

{

    NSDate *now = [[NSDate alloc] init];

    NSLocale *locale = [NSLocale currentLocale];

    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];

    [dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];

    [dateFormatter setLocale:locale];


    [label setString:[dateFormatter stringFromDate:now]];

    [dateFormatter release];

    [now release];

}



// on "init" you need to initialize your instance

-(id) init

{

// always call "super" init

// Apple recommends to re-assign "self" with the "super" return value

if( (self=[super init])) {

// create and initialize a Label

                // 멤버 변수를 사용하도록, 이전 소스에서 한부분만 수정. 옆에 폰트도 바꿨음. 

label = [CCLabelTTF labelWithString:@"Hello World" fontName:@"AppleGothic" fontSize:32];


// ask director the the window size

CGSize size = [[CCDirector sharedDirector] winSize];

// position the label on the center of the screen

label.positionccp( size.width /2 , size.height/2 );

// add the label as a child to this Layer

[self addChild: label];

        

        [self schedule:@selector(updateTime) interval:1];// 이것이 바로, 매초마다 호출되게 하는 스케줄러 설정부분.

}

return self;

}

 

끝났다. 여러분은 이제 시계를 만들었다.

소스에 특별한 설명을 할만한 부분이 없으나, update함수를 매초마다 호출하게 하는 방법은 어떻게 하나?? 고민하였을텐데. 바로 위에 나오는 schedule 메소드를 사용하면 된다. 사용하는 문법은 xcode에서 타이핑하면 줄줄줄 바로 나온다. 여기서 등장하는 @selector가 무엇이냐면, 우리가 C/C++을 할때에는 함수 포인터를 사용해서, 타이머 콜백등을 등록해두거나 하는데, objective C 에서는 그렇게 하지 않고, selector라고 하는 것을 사용한다, 함수를 만들고 선언하면, 각 함수는 고유한 SEL값을 가지게 되는데, 그 값을 관리하는 테이블에 실제로 그 함수로 연결해주는 주소를 따로 관리하고 있다. 우리는 콜백을 달거나, 특별히 딜레이를 줘야 할경우가 생긴다면, 앞으로 @selector()를 사용하면 된다.

interval은 1은 1초마다를 뜻한다. 1/60을 하면 60프레임이 되는거고, 아무것도 안넣으면 매프레임마다 호출되게 된다.


또 본인이 개발할때 폰트를 Marker Felt만 써야 되는줄 알고 완전 힘들게 이미로 분리해서 하나씩 썼었는데, 전혀 그럴필요가 없다. 앞으로 cocos2d를 사용해서 글자를 찍고 싶으면 아래 리스트에 나오는 폰트중 아무거나 하나 골르면 된다. 그리고, 최근에 추가된 여러폰트들도 있을것으므로, 인터넷 검색을 통해서 찾아서 사용하면 된다.


CCLabelTTF가 지원하는 폰트들(외부폰트를 사용할수도 있음)

 

Family name: AppleGothic

Font name: AppleGothic

Family name: Hiragino Kaku Gothic ProN

Font name: HiraKakuProN-W6

Font name: HiraKakuProN-W3

Family name: Arial Unicode MS

Font name: ArialUnicodeMS

Family name: Heiti K

Font name: STHeitiK-Medium

Font name: STHeitiK-Light

Family name: DB LCD Temp

Font name: DBLCDTempBlack

Family name: Helvetica

Font name: Helvetica-Oblique

Font name: Helvetica-BoldOblique

Font name: Helvetica

Font name: Helvetica-Bold

Family name: Marker Felt

Font name: MarkerFelt-Thin

Family name: Times New Roman

Font name: TimesNewRomanPSMT

Font name: TimesNewRomanPS-BoldMT

Font name: TimesNewRomanPS-BoldItalicMT

Font name: TimesNewRomanPS-ItalicMT

Family name: Verdana

Font name: Verdana-Bold

Font name: Verdana-BoldItalic

Font name: Verdana

Font name: Verdana-Italic

Family name: Georgia

Font name: Georgia-Bold

Font name: Georgia

Font name: Georgia-BoldItalic

Font name: Georgia-Italic

Family name: Arial Rounded MT Bold

Font name: ArialRoundedMTBold

Family name: Trebuchet MS

Font name: TrebuchetMS-Italic

Font name: TrebuchetMS

Font name: Trebuchet-BoldItalic

Font name: TrebuchetMS-Bold

Family name: Heiti TC

Font name: STHeitiTC-Light

Font name: STHeitiTC-Medium

Family name: Geeza Pro

Font name: GeezaPro-Bold

Font name: GeezaPro

Family name: Courier

Font name: Courier

Font name: Courier-BoldOblique

Font name: Courier-Oblique

Font name: Courier-Bold

Family name: Arial

Font name: ArialMT

Font name: Arial-BoldMT

Font name: Arial-BoldItalicMT

Font name: Arial-ItalicMT

Family name: Heiti J

Font name: STHeitiJ-Medium

Font name: STHeitiJ-Light

Family name: Arial Hebrew

Font name: ArialHebrew

Font name: ArialHebrew-Bold

Family name: Courier New

Font name: CourierNewPS-BoldMT

Font name: CourierNewPS-ItalicMT

Font name: CourierNewPS-BoldItalicMT

Font name: CourierNewPSMT

Family name: Zapfino

Font name: Zapfino

Family name: American Typewriter

Font name: AmericanTypewriter

Font name: AmericanTypewriter-Bold

Family name: Heiti SC

Font name: STHeitiSC-Medium

Font name: STHeitiSC-Light

Family name: Helvetica Neue

Font name: HelveticaNeue

Font name: HelveticaNeue-Bold

Family name: Thonburi

Font name: Thonburi-Bold

Font name: Thonburi

 
 

위의 시계어플을 실행시킨 동영상을 마지막으로 첨부한다.

 

다음포스트에서 sprite에 대해서 이야기 해보자.
 

'코딩하고 > iOS' 카테고리의 다른 글

VoodooHDA 64비트 빌드 그리고, nVidia HDMI 제거.  (2) 2011.08.15
iOS용 게임 개발기 -5-  (0) 2011.08.10
iOS용 게임 개발기 -4-  (0) 2011.08.01
iOS용 게임 개발기 -3.1-  (0) 2011.07.11
iOS용 게임 개발기 -3-  (0) 2011.07.11
블로그 이미지

커뉴

이 세상에서 꿈 이상으로 확실한 것을, 인간은 가지고 있는 것일까?

,
지난 포스트에서 약속했던바와 같이 이번 포스트에서는 정말 cocos2d의 기초 부분을 살짝 확인해보는 데 의미를 두는 글을 쓰도록 하겠다.  앞으로 게임을 개발 하든, 어플을 개발하든 기본, 기초만 알고 있으면, 나머지 필요한 부분은 각종 인터넷 매뉴얼을 본다거나, 샘플 코드를 보면서 따라 해도 아무런 무리가 될것이 없다.

본인 역시도, cocos2d를 사용하면서, "내가 하고 싶은것이 이런건데, 이건 대체 어떻게 해야 하나???" 고민하는 것보다, 인터넷 검색을 해서 바로 필요한 부분을 찾고, 기초적인 내용을 조합해서 해당 기능이 동작하도록 한 것이 대부분이다.

게임 개발하면서 가장 중요했던 부분이 자료구조인데, 이부분은 C/C++의 것을 그대로 사용할까 하다가, 이왕이면 Objective C의 것을 사용하고자 마음먹고, 이부분도 cocos2d를 보면서 같이 공부했는데 아무런 어려움이 없었다. 여러분들도 그러할것이다.!!

그러면, 아래 소스를 한번 보자.

// main.m file.
#import
<UIKit/UIKit.h>


int main(int argc, char *argv[]) {

    

    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

    int retVal = UIApplicationMain(argc, argv, nil, @"AppDelegate");

    [pool release];

    return retVal;

}


위 파일은 프로젝트를 만들면 자동으로 생성되는 main.m파일인다, 우리가 이전에 C언어를 사용하면, 하나의 프로그램에 엔트리를 만드는데 보통 main함수를 만들어 썼다. objective c 도 마찬가지이다. 위에서 처럼, 자동해제해주는 메모리 풀을 만들어주고,  AppDelegate를 찾아서 실제 제어를 넘겨준다.

우리는 앞으로 main.m을 건드릴은 거의 없다. 본인은 전혀 없었다.

// AppDelegate.h file
#import
<UIKit/UIKit.h>


@class RootViewController;


@interface AppDelegate : NSObject <UIApplicationDelegate> {

UIWindow *window;

RootViewController *viewController;

}


@property (nonatomic, retain) UIWindow *window;


@end

 위 파일은 바로전에 실제 제어를 넘겨받는 AppDelegate의 헤더 파일이다. 어떤 내용이 있다 궁금하니까 한번 열어보는 정도의 의미를 두면 되는데, AppDelegate 는 NSObject를 상속받고, 그 멤버로는 window와 viewController가 있다. 아래는 @property는 나중에 쓰다보면, 알게 되지만, 간단하게 말해서 우리가 프로그래밍을 할때, 어떠한 클래스의 멤버 변수를 셋팅하거나 가져오거나 할수 있도록 만드는데, 그것을 objective C에서는 위와 같은 방법으로 선언하고, 실제 구현파일 즉 *.m 에서 @synthesize 를 이용해서 그 바디를 자동으로 구현하도록 한다. 나중에 외부 클래스에서 window라는 변수를 접근할수 있게 해주는 것이다.  이걸 setter와 getter라고 한다.

여기서 retain이라고 하는것도 굉장히 중요한데, 이부분은 나중에 따로 메모리 관리를 이야기 하면서 하나의 주제로 포스팅하겠다. 메모리 릭 나오고, 죽고 하는 문제 때문에 정말 피똥싼적있는데,. 다 저런것들 때문이었다..

그러면 이제는 실제 구현되는 부분으로 가보자.

//

//  AppDelegate.m

//  


//

//  AppDelegate.m

//  cocos2dTest

//

//  Created by Yongsu Kim on 11. 7. 11..

//  Copyright iinov.com 2011. All rights reserved.

//


#import "cocos2d.h"


#import "AppDelegate.h"

#import "GameConfig.h"

#import "HelloWorldLayer.h"

#import "RootViewController.h"


@implementation AppDelegate


@synthesize window;


- (void) removeStartupFlicker

{

//

// THIS CODE REMOVES THE STARTUP FLICKER

//

// Uncomment the following code if you Application only supports landscape mode

//

#if GAME_AUTOROTATION == kGameAutorotationUIViewController


// CC_ENABLE_DEFAULT_GL_STATES();

// CCDirector *director = [CCDirector sharedDirector];

// CGSize size = [director winSize];

// CCSprite *sprite = [CCSprite spriteWithFile:@"Default.png"];

// sprite.position = ccp(size.width/2, size.height/2);

// sprite.rotation = -90;

// [sprite visit];

// [[director openGLView] swapBuffers];

// CC_ENABLE_DEFAULT_GL_STATES();

#endif // GAME_AUTOROTATION == kGameAutorotationUIViewController

}

- (void) applicationDidFinishLaunching:(UIApplication*)application

{

// Init the window

window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];

// Try to use CADisplayLink director

// if it fails (SDK < 3.1) use the default director

if( ! [CCDirector setDirectorType:kCCDirectorTypeDisplayLink] )

[CCDirector setDirectorType:kCCDirectorTypeDefault];

CCDirector *director = [CCDirector sharedDirector];

// Init the View Controller

viewController = [[RootViewController alloc] initWithNibName:nil bundle:nil];

viewController.wantsFullScreenLayout = YES;

//

// Create the EAGLView manually

//  1. Create a RGB565 format. Alternative: RGBA8

// 2. depth format of 0 bit. Use 16 or 24 bit for 3d effects, like CCPageTurnTransition

//

//

EAGLView *glView = [EAGLView viewWithFrame:[window bounds]

  pixelFormat:kEAGLColorFormatRGB565 // kEAGLColorFormatRGBA8

  depthFormat:0 // GL_DEPTH_COMPONENT16_OES

];

// attach the openglView to the director

[director setOpenGLView:glView];

// // Enables High Res mode (Retina Display) on iPhone 4 and maintains low res on all other devices

// if( ! [director enableRetinaDisplay:YES] )

// CCLOG(@"Retina Display Not supported");

//

// VERY IMPORTANT:

// If the rotation is going to be controlled by a UIViewController

// then the device orientation should be "Portrait".

//

// IMPORTANT:

// By default, this template only supports Landscape orientations.

// Edit the RootViewController.m file to edit the supported orientations.

//

#if GAME_AUTOROTATION == kGameAutorotationUIViewController

[director setDeviceOrientation:kCCDeviceOrientationPortrait];

#else

[director setDeviceOrientation:kCCDeviceOrientationLandscapeLeft];

#endif

[director setAnimationInterval:1.0/60];

[director setDisplayFPS:YES];

// make the OpenGLView a child of the view controller

[viewController setView:glView];

// make the View Controller a child of the main window

[window addSubview: viewController.view];

[window makeKeyAndVisible];

// Default texture format for PNG/BMP/TIFF/JPEG/GIF images

// It can be RGBA8888, RGBA4444, RGB5_A1, RGB565

// You can change anytime.

[CCTexture2D setDefaultAlphaPixelFormat:kCCTexture2DPixelFormat_RGBA8888];


// Removes the startup flicker

[self removeStartupFlicker];

// Run the intro Scene

[[CCDirector sharedDirector] runWithScene: [HelloWorldLayer scene]];

}



- (void)applicationWillResignActive:(UIApplication *)application {

[[CCDirector sharedDirector] pause];

}


- (void)applicationDidBecomeActive:(UIApplication *)application {

[[CCDirector sharedDirector] resume];

}


- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application {

[[CCDirector sharedDirector] purgeCachedData];

}


-(void) applicationDidEnterBackground:(UIApplication*)application {

[[CCDirector sharedDirector] stopAnimation];

}


-(void) applicationWillEnterForeground:(UIApplication*)application {

[[CCDirector sharedDirector] startAnimation];

}


- (void)applicationWillTerminate:(UIApplication *)application {

CCDirector *director = [CCDirector sharedDirector];

[[director openGLView] removeFromSuperview];

[viewController release];

[window release];

[director end];

}


- (void)applicationSignificantTimeChange:(UIApplication *)application {

[[CCDirector sharedDirector] setNextDeltaTimeZero:YES];

}


- (void)dealloc {

[[CCDirector sharedDirector] end];

[window release];

[super dealloc];

}


@end

 
본인은 보면서 "이게 뭐지???" 라는 생각부터 들었다. 대체 어디로 제어권이 넘어가는거야!! 하고 버럭 버럭 하고 앉았었으나, 그건  iOS 어플이 어떻게 돌아가는지 몰라서 그런거였고.. 지금 보면 굉장히 심플한 것이었다, applicationDidFinishLaunching 이것이 바로, "론치가 끝나면 여기로 오세요"를 의미하는 함수이다.

사실 여기 부분도, 기존의 부분은 거의 수정할것이 없다. 본인은 추가는 생각보다 많이 했다. 나중에 소스를 하나씩 하나씩 보면서 설명하겠지만, 다른 메뉴의 전환, 레벨 조절, 점수 저장 등등등 설계자체가 너무 좀 크게 해서 그런지, 그들을 서로 연결해주는 게이트웨이가 필요했는데, 본인은 그 게이트웨이를 여기 이 delegate로 정했다. 다른 게임을 설계할때에도 하나의 파일에 전부다 구현할수가 없고, 하나의 클래스에 전부다 넣을수 없으며, cocos2d의  scene이나 layer하나에 전부 넣을수 없다. 그때 서로 다른 클래스, scene, layer간의 필요한 정보의 교환을 할수 있는 곳이 필요한데, 바로 이런곳에서 하면 된다. 


물론 그 계층 구조를 어떻게 만드냐에 따라서, layer들은 상위  scene을 통해서 하면되고, scene들만 delete를 통해서 의사소통하면 된다. 본인의 경우에는 이러한 구조로 작업을 하였으며, 만들고 나서보니 하나의 게임 프레임웍이 되어, 다른 게임을 또 하나 만들고 있다. 

위 소스에서 가장 중요한 부분은 바로 다음 부분이다.

// Run the intro Scene

[[CCDirector sharedDirectorrunWithScene: [HelloWorldLayer scene]];


이곳이 이제 실제로 cocos2d의 개념 이해가 필요한 부분인데.

위의 코드가 뜻하는 바는, "HelloWorldLayer의 Scene으로 넘어가라."이다.


이제 scene이 의미하는 것은 대체 뭔가 궁금해질것이다. 궁금해야 올바른 개발자이다. 처음에 scene의 개념을 모호하게 이해 못해서, 좀 어리 버리한짓을 많이 했는데, 나름 그 개념을 이해하고나, 현실에서 우리가 흔히 말하는 영화의 씬~, 애니메이션의 씬~, 드라마의 씬~ 바로 그것과 똑같은 것이다. 영화를 예를 들면, 촬영을 할때, 무슨씬 무슨 컷 이렇게 촬열이 들어간다면, 그 씬은 하나의 큰 주제를 의미할수 있다. 가령, 철수와 영희의 격투씬 을찍으면 그 씬은 정해져있고, 그씬안에 들어갈 내용들을 촬영하고 스토리로 나누게 되는데, 그 씬안에 들어가는 것들이 layer다.


여러분은 이제 cocos2d를 구성하는 scene과 layer의 의미를 이해했다. 물론 이론적으로정확히 설명을 하면 아래와 같이 설명할수 있다. 

Scenes

A “scene” in Cocos2d is just a special sort of node that acts as the ultimate parent for all other nodes that are visible. --> 이것이 핵심!! 

You can use this however you like, but typical usage is probably to make one scene for the “real” playable part of your game, and then use other scenes for the title page, high scores list, options, and so on. A scene is represented by the CCScene class.

A scene is “running” if it is the scene that is visible, has actions that are progressing, and so on. Only one scene can be running at a time. However, it's possible to push another scene on top of the current one, pausing the current one and running the new one; then later pop that new one and resume running the first. Or, you can have one scene entirely replace another (which is usually preferable, since it uses less memory).

This pushing/popping or replacing of scenes is done by the director (CCDirector). You've already seen this if you've poked around much in the project template. Look in the application delegate (e.g., in Lesson1AppDelegate.m or whatever it's called in your project). At the bottom of the applicationDidFinishLaunching method, you'll find a line like this:

	[[CCDirector sharedDirector] runWithScene: [HelloWorld scene]];

This tells the director to start running the given scene (HelloWorld).

To replace the running scene with another – for example, when the user taps the “Play” button on the menu screen, or when the game is over and you want to go back to the main menu – simply call replaceScene on the director:

	[[CCDirector sharedDirector] replaceScene: [SomeOtherScene scene]];

This terminates the current scenes, and starts the next one. You could later restart the first (or any other) by calling replaceScene again.

If you wanted to just pause the current scene instead, use pushScene instead of replaceScene; then you would call popScene later to terminate the new one, and resume the old. But use this sparingly, since memory on the iPhone is limited, and all scenes on the stack stay in memory.


이제는 helloWorldLayer로 가보자.

// HelloWorldLayer.h

#import
"cocos2d.h"


// HelloWorldLayer

@interface HelloWorldLayer : CCLayer

{

}


// returns a CCScene that contains the HelloWorldLayer as the only child

+(CCScene *) scene;


@end


뭐 큰내용이 없다. Layer이기 때문에, CCLayer를 상속받았고, 클래스 메소드로 scene이라는 메소드를 가지고 있다. + 표시가 바로 이 함수는 클래스 메소드 이다. 즉, "해당 클래스가 생성될때 새로 생성되는 것이 아닌(Instance가 아닌), static 메소드입니다." 라는 것이다. 해당 클래스를 생성하지 않아도 호출할수 있는 함수 정도로 이해해두자.

scene함수는 아래소스를 보면 그 body가 구현되어 있다. Scene을 하나 만들어서, 거기 밑에다가 HelloWorldLayer를 하나 만들어서 자식으로 달고, scene을 반환하도록 되어 있다. 좀 더 복잡한 소스를 나중에 보면서 좀더 자세히 설명하겠지만, 지금은 그냥 저렇게 하위에 레이어를 하나 달아주는것이구나정도로 이해하면 된다. 위에서 말했던 것처럼 Scene아래에 layer가 있으므로, 우리는 아래 코드로 Scene을 만들고,Layer도 하나 만들어서 사용할수 있게 한것이다.

//

//  HelloWorldLayer.m

//  



// Import the interfaces

#import "HelloWorldLayer.h"


// HelloWorldLayer implementation

@implementation HelloWorldLayer


+(CCScene *) scene

{

// 'scene' is an autorelease object.

CCScene *scene = [CCScene node];

// 'layer' is an autorelease object.

HelloWorldLayer *layer = [HelloWorldLayer node];

// add layer as a child to scene

[scene addChild: layer];

// return the scene

return scene;

}


// on "init" you need to initialize your instance

-(id) init

{

// always call "super" init

// Apple recommends to re-assign "self" with the "super" return value

if( (self=[super init])) {

// create and initialize a Label

CCLabelTTF *label = [CCLabelTTF labelWithString:@"Hello World" fontName:@"Marker Felt" fontSize:64];


// ask director the the window size

CGSize size = [[CCDirector sharedDirector] winSize];

// position the label on the center of the screen

label.positionccp( size.width /2 , size.height/2 );

// add the label as a child to this Layer

[self addChild: label];

}

return self;

}


// on "dealloc" you need to release all your retained objects

- (void) dealloc

{

// in case you have something to dealloc, do it in this method

// in this particular example nothing needs to be released.

// cocos2d will automatically release all the children (Label)

// don't forget to call "super dealloc"

[super dealloc];

}

@end


scene함수에서 [HelloWorldLayer node];이 부분이 의미하는 바는 " HelloWorldLayer의 node 메소드를 호출하라." 그러면 cocos2d의 node 함수는 아래와 같이 되어 있다.

+(id) node

{

return [[[self alloc] init] autorelease];

}

여기도 클래스 메소드인데, 바로 자기 자신을 하나 생성하고(HelloWolrdLayer클래스를 위한 공간을 만들고) init 메소드르 호출하라.(autorelease도 다음에 다루겠다.)

init 은 바로 위 소스에 나오는 것처럼, 아래와 같다.

// on "init" you need to initialize your instance

-(id) init

{

// always call "super" init

// Apple recommends to re-assign "self" with the "super" return value

if( (self=[super init])) {

// create and initialize a Label

CCLabelTTF *label = [CCLabelTTF labelWithString:@"Hello World" fontName:@"Marker Felt" fontSize:64];


// ask director the the window size

CGSize size = [[CCDirector sharedDirectorwinSize];

// position the label on the center of the screen

label.position =  ccp( size.width /2 , size.height/2 );

// add the label as a child to this Layer

[self addChild: label];

}

return self;

}

여기서 -는 이제 일반 함수이다. instance함수.(꼭 생성후 alloc후 사용가능한 함수)

여기가 바로.. 우리가 화면에서 보던 "Hello World"를 찍어주는 부분이다. 코드의 내용의 자세한 부분은 다음에 해당 주제가 나올때 다시 이야기 하기로 하고, 여기까지 왔으면 이제 cocos2d를 이용해서, 문자열을 찍어주는 간단한 어플은 이제 만들수 있게 된다. 전광판과 같은 효과라던가, 그런 화려한 효과는 아니더라도, 내가 찍고자하는 내용을 원하는 규칙에 맞게 이제 콘트롤 가능한 것이다. 

다음 포스트는 sprite에 대해서 이야기 하도록 하겠다. cocos2d의 존재 목적이 바로 sprite이다. 우리가 게임을 만들때, 수많은 이미지들을 사용하고, 각종이펙트나, 애니매이션 효과를 구현할때에도 역시 이미지들 즉, sprite를 이용한다. 그것을 우리가 정말 빡세게 하나 하나, 장인정신으로 한땀 한땀 손수 만들수 있지만, 이미 정말 잘만들어진 솔루션이 있고, 공짜다. 그게 바로  여러분이 보고 있는 cocos2d라는것이다.

다음 주제를 최대한 빨리 준비해서 다시 포스트 하도록 하겠다. 


추신)
본 포스트들은 완전히 개인적인 목적으로 글을 쓰는 것이고, 개발기는 본인이 iOS용 게임 개발을 공부하면서 처음 개발한 BlueOcean을 개발하면서 경험한 것들을 정리하는 내용들이다. BlueOcean은 실제로 아래 링크에서 아직도 살아있다.
http://itunes.apple.com/us/app/blue-ocean/id430842838?l=ko&ls=1&mt=8







 

'코딩하고 > iOS' 카테고리의 다른 글

iOS용 게임 개발기 -5-  (0) 2011.08.10
iOS용 게임 개발기 -4.1-  (0) 2011.08.02
iOS용 게임 개발기 -3.1-  (0) 2011.07.11
iOS용 게임 개발기 -3-  (0) 2011.07.11
iOS용 게임 개발기 -2-  (0) 2011.07.09
블로그 이미지

커뉴

이 세상에서 꿈 이상으로 확실한 것을, 인간은 가지고 있는 것일까?

,
말나온김에, 내가 만든 게임 플레이 동영상을 첨부해본다.

동영상 시뮬레이터.



위 플레이 영상은 정말 가장 쉬운 레벨들인데도 불구하고, 개발자 본인은.. 단박에 클리어 하지 못하고 있다. 

물론 디바이스에 넣어서 플레이했을때는 저 영상보다 훨씬 더 나은 실력을 발휘 할수 있다.!!!

45레벨 모두를 클리어하는데, 대략 1주일이 걸렸다. 보기에는 쉬우나, 뒤로 갈수록 정말 뒷목 잡고 쓰러질뻔한 게 한두번이 아니다. 내가 만들었는데, 왜 내가 클리어를 이렇게 힘들게 해야 하는지.. 정말 출제자의 의도를 알아도 풀수가 없다니....

다음포스트에서, 다시 보기로 하자. 

 

'코딩하고 > iOS' 카테고리의 다른 글

iOS용 게임 개발기 -4.1-  (0) 2011.08.02
iOS용 게임 개발기 -4-  (0) 2011.08.01
iOS용 게임 개발기 -3-  (0) 2011.07.11
iOS용 게임 개발기 -2-  (0) 2011.07.09
iOS용 게임 개발기 -1-  (0) 2011.07.08
블로그 이미지

커뉴

이 세상에서 꿈 이상으로 확실한 것을, 인간은 가지고 있는 것일까?

,