개발 프로비저닝으로 열심히 개발을 해서 실제 기기에서도 잘 돌아가는 것을 확인했다면 이제 앱스토어에 올려야겠지.


애플 개발자 사이트로 가서 배포용 프로비저닝 프로파일을 우선 만들어야겠다.

나중에 코드 사이닝에 사용해야하니깐...




Provisioning Profiles 가서 + 눌러 위 화면이 나오면 이제 Distribution 아래에 App Store 를 선택하고 [Continue]


Select App ID 가 나오면 해당 앱 아이디를 선택하고 컨티뉴!!!


Select Certificates 가 나오면 아래쪽에서 해당 아이디 선택하고 컨티뉴!!


Name this profile and generate 에 나오면 이름 정해주고 아래에 [Generate] 클릭!


다음 화면에서 다운로드한 후, 파인더에서 찾아 더블클릭!!


그러면 배포용 프로비저닝 프로파일은 준비가 된거고...


Xcode로 가서 해당 프로젝트를 열자.




위에 보이는 것처럼 Manage Schemes 를 클릭!


해당 프로젝트 명을 선택하고 아래에 [Edit] 클릭!



아래 창이 나오면 왼쪽에 Archive 를 선택하고 오른쪽에서 Archive Name 적어준다.

그리고 Ok!




평온한 Xcode 화면에서 왼쪽에 Products 그룹 아래에 iOS용 앱을 선택하고 Build settings 를 연다.




Code Signing Identity 를 iOS Distribution으로 선택한다.


그리고 나서 아래처럼 Archive 를 선택하면 앱스토어에 올릴 패키지를 딱 만들어준다.




정리하면 

배포용 프로비저닝 프로파일 만들기

Manage schemes 에 가서 해당 프로젝트의 Archive 이름을 정해주고...  Archieve는 미리 Release 로 빌드가 되는거고..

코드 사이닝을 배포 로 설정하고 

Archive 명령 때리기!!!!



cocos2d-x 3.0 beta2 를 작업한 게임을 이렇게 Archive를 시켰더니 빌드 하는 중에 엄청난 에러가 발생했다.


프로젝트 설정에 기본적으로 64비트 아키텍트가 들어가 있어서 에러가 발생하는 거란다.

cocos2d-x 3.0 beta2.. 아니 cocos2d-x 는 64비트 지원이 안 된다.


그래서 다시 build settings 에 가서 architect 부분을 수정해줘야했다.




Architectures 에 $(ARCHS_STANDARD_32_BIT) 로 수정하고

Valid Architectures 에서 arm64 제거해야했다.


이렇게 수정을 하고 다시 Archive 시키면 한참 걸려서 빌드를 마치고 오거나이저가 딱 뜬다!



오거나이저가서 아래처럼 Archives를 선택하면 잘 만들어진 앱이 딱 있다.


오른쪽에 있는 Validate 를 눌러서 아카이브에 문제가 있는지 없는지 체크가 가능하다.

버튼 눌러보면 빠진 이미지가 있다거나 하는 문제점을 알려주는데 수정하고 다시 아카이브하고 또 Validate.. ㅎㅎ


cocos2d-x 3.0 beta2 로 작업한 게임인데 CFBundleIconFiles?? 인가에 설정되어 있는 Icon.png와 Icon@2x.png 이 없다는 오류가 나타났다. 

프로젝트 디렉토리 아래에 proj.ios_mac 아래에 ios 디렉토리에 보면 온갖 크기의 아이콘들이 있는데, 그중에 57x57 이미지를 복사해서 Icon.png로 이름을 변경하고, 114x114 이미지를 복사해서 Icon@2x.png로 이름을 변경해줬다.

cocos2d-x 3.0 에서 아직 각각의 아이콘을 Info.plist 에서 설정한 값으로 우째하는 모양인데...

다음에 아이콘 관련해서 정리 좀 해놔야겠다.



결국에 문제가 없다는 말이 나오면 이제 Distribute 를 눌러서 앱스토어에 앱을 제출을 한다.


아! 제출이 가능하려면 우선에 개발자 사이트에서 앱을 만들어두고 설정, 이미지 업로드 등..다 마치고 Prepare for upload 상태가 되어있어야 한다.




다음에 읽어보면 기억이 나겠지???





Posted by 똑똑한 영장류



새 그림을 이용해서 스프라이트를 만들어 줬는데, 이 스프라이트가 계속 날개짓을 하도록 만들고 싶은거다.


날개짓을 하는 동작을 여러장으로 이미지로 구현하고 그 이미지들을 연속적으로 보여주면 날개짓을 하는것으로 보일터... 


이미지 작업은 별로의 능력으로 커버 하도록 하고...


이미지가 준비되면, Zwoptex 를 이용해서 plist 파일과 여러장의 이미지가 하나로 합쳐진 이미지를 만든다.

이건 Zwoptex 사용법을 알아야 하는 바... 검색을 이용하시고...


설명은 새로 하고 테스트는 별 모양의 스프라이트가 왼쪽 오른쪽 살짝살짝 회전을 반복하는 거라서 이름이 바뀐다.


결과적으로 star-ani_default.pliststar-ani_default.png 가 준비되었다고 가정한다.


아래는 star-ani_default.png 이다. 12장의 이미지가 합쳐져 있다.

왼쪽부터 오른쪽으로 순서대로 보여주면 별이 까딱까딱하는 모습이 될 것이다.

Zwoptex 를 이용해서 합쳐지기 전에 각각의 파일들의 이름은 star01.png, star02.png...이다.




소스는...


//star-ani_default.plist 를 읽어 각각의 이미지들, 즉 star01.png, star02.png...를 캐시에 넣는다.

SpriteFrameCache::getInstance()->addSpriteFramesWithFile("star-ani_default.plist");


//최초로 화면에 찍힐 스프라이트를 만들어 준다.

Sprite *star = Sprite::create( "star01.png" );

star->setPosition( 100,100);


// 여기서부터는 에니메이션을 만드는 과정    


// animation을 만들 각각의 이미지를 담을 공간을 만들어 두자.

cocos2d::Vector<SpriteFrame*> animFrames;


// star01.png, star02.png 등 파일명을 가지고 있을 변수를 하나 만든다.

char str[100] = {0};


// 캐시 해놓은 이미지를 하나씩 가져와서 

    for (int i=1; i<=12; i++) {

        sprintf(str, "star%02d.png",i); // i 값에 따라 star01.png, star02.png..등이 된다.

        // 만들어진 파일명의 이미지를 캐시에서 가져와 

        SpriteFrame* frame = SpriteFrameCache::getInstance()->getSpriteFrameByName(str);

        // animFrames 에다가 넣는다.

        animFrames.pushBack(frame);

    }


// 에니메이션에 사용할 이미지들이 준비되었다.

// Animation이랑 Animate 가 이름이 비슷하면서 역할이 헤깔릴 수 있는데, 

// Animation은 설정이라고 생각하고 움직이도록 하는 액션은 Animate 라고 생각하면 될거 같다.

// 준비된 이미지 프레임들을 0.1초마다 바꿔보여주도록 설정해서 animation을 만든다.    

Animation *animation = Animation::createWithSpriteFrames(animFrames,0.1f);


// animation 설정을 이용해서 Animate 액션을 만든다.

Animate *animate = Animate::create(animation);


// 계속 까딱까딱 움직이도록 RepeatForever 로 잡아준다.    

auto actionStar = RepeatForever::create(animate);



// 혼자 덜렁 만들어져 있던 스프라이트에 에니메이션 액션을 실행하도록 시킨다.

star->runAction(actionStar);


용어가 조금 헤깔리지만, 결국엔 여러장의 이미지를 준비해서 Animation 을 만들고 Animate 액션을 만들어서 스프라이트에게 실행하도록 시키면 된다.


에니메이션시키는 방법이 몇가지 있는데, 차이점은 이미지들을 가져와서 animFrames 처럼 프레임 셋을 만드는 부분에 차이가 있다.


나는....이미지 작업이 잘 되었으면 Zwoptex를 이용해서 깔끔하게 패키지를 하고 사용하는 것을 선호한다.


위 소스에서 처름에 혼자 덜렁있는 스프라이트를 만들 때, plist 를 먼저 처리하고 거기서 star01.png 를 가져와서 만들어 줄 수 있다.

그러면, 최초 스프라이트의 생성 위치가 plist 처리 이후가 되겠네.


해보니, 에니메이션은 그래픽 노가가다 대부분이다. 소스 작성은 별 어려움이 없었다.


이상!











Posted by 똑똑한 영장류

쪼매난 스프라이트 여러개가 특이한 모습을 나타내는 기능이라고나 할까...


예를 들면...음...

불꽃 놀이를 보면, 전체 모양은 커다란 원을 나타내면서 펑! 터지지만, 그 원을 이루는 하나하나는 작은 불빛들이잖아?


그 작은 불빛이 파티클! 즉, 쪼가리 이미지이다.


전체 불꽃의 모양은 동그랗기도 하고, 비처럼 쏟아져내리기도 하고 가는 선처럼 휘~익 이어지면서 날아가기도 하고...

하지만 그런 전체 모양을 나타낼 때 필요한거는 쪼매난 불빛이지.


cocos2d-x 에서, 비슷한 개념으로 사용할 수 있는 것이 파티클 시스템이다.


본부 설명 페이지는 아래...


http://www.cocos2d-x.org/reference/native-cpp/V3.0beta2/d1/dfd/group__particle__nodes.html


기본적으로 아래의 방법? 모양?? 파티클시스템을 제공하는데, 쪼매난 이미지를 이용해서 화염이 몽실몽실거리는거라(ParticleFire), 불꽃놀이처럼 펑 터져서 흩어진다거나(ParticleFirework), 동그랗게 몽실거리는 태양모양이라던가(ParticleSun)... 등등을 만들 수 있다. 


ParticleFire

ParticleFireworks

ParticleSun

ParticleGalaxy

ParticleFlower

ParticleMeteor

ParticleSpiral

ParticleExplosion

ParticleSmoke

ParticleSnow

ParticleRain



그리고, 매뉴얼에 보이는 것이 ParticleSystem, ParticleSystemQuad 가 있는데, 

요 파티클 시스템이라는 녀석에게 불꽃놀이처럼 보이도록 해봐! 꽃처럼 보이도록 해봐! 이렇게 시키는거다.


ParticleSystemQuad 는 ParticleSystem 에다가 몇가지 기능들이 더 추가된 거라고 한다.


아래 내용이 차이점.

  • Particle size can be any float number.
  • The system can be scaled
  • The particles can be rotated
  • It supports subrects
  • It supports batched rendering since 1.1


필요에 따라서 선택하면 되겠다.



자...그럼, 어떻게 사용을 하나...?


파티클로 이용할 쪼매난 이미지는.... 

cocos2d-x 의 sample 디렉토리 아래에 image 디렉토리에 있는 fire.png 를 이용하자. 


void PlayLayer::doParticleDemo()

{

    ParticleSystem* particleSys = ParticleFire::create();

    particleSys->retain();

   

    particleSys->setTexture(Director::getInstance()->getTextureCache()->addImage("fire.png"));   


    particleSys->setPosition(150,480);

    this->addChild(particleSys, 10);

   

}


먼저, ParticleSystem 혹은 ParticleSystemQuad 를 만드는데, 위의 코드처럼 원하는 모습의 Particle어쩌구저쩌구 를 지정해 주면 된다.

예에서는 쪼가리 이미지를 이용해서 ParticleFire 라는 전체 모양을 만들어 보는거다. 저 자리에 다른 Particle 항목을 사용할 수 있겠다.


그리고나서는, Fire 를 만드는데 사용할 , 파티클로 사용할 이미지 파일을 설정해주고, 위치 잡아서 레이어에 붙여준다.

별 어려운 개념은 없네.

 

이렇게 해서 실행을 시켜보면, 모닥불의 화염같은 모양으로 몽실몽실 거리는 것을 볼 수 있다.

fire.png 라는 쪼매난 이미지를 이용해서 모닥불의 화염같이 에뮬레이션? 해 주는 거다.


저렇게 하니까, 한 자리에서 계속 몽실거리는데, 함수 몇 개를 찾아보니 아래의 함수를 발견할 수 있었다.


    // 전체 이미지? 전체 불모양이 지속되는 시간을 설정해줄 수 있다. 

    particleSys->setDuration(3.0f);

    // 각각의 파티클 이미지가 몽실몽실거리고 사라질 때까지의 시간을 설정해 줄 수 있다.

    particleSys->setLife(1.0f);


이 두 함수 외에도, ParticleXXXXXX 마다 사용에 필요한 함수들이 차이가 조금 있는 것 같은데, 사이트 매뉴얼 잘 살펴보고 작성하면 되겠다.



오늘은 캡쳐 생략! ㅠㅠ



























Posted by 똑똑한 영장류

게임을 만들면서 종료시점의 환경이나, 최고 점수 등 간단한 데이터들을 저장할 필요가 있는데, cocos2d-x 3.0 beta2 에서는 아래의 클래스를 제공한다.


UserDefault


아래 링크로 가서 자세한것은 살펴보면 좋고...

http://www.cocos2d-x.org/reference/native-cpp/V3.0beta2/db/d94/classcocos2d_1_1_user_default.html


사용법이 아주 쉬워서 그다지 설명도 필요없다.



기본적으로 key : value 의 형태로 데이터를 저장한다.


저장할 수 있는 데이터 타입은 아래와 같다.


bool

int

float

double

std::string

Data


Data 가 익숙하지 않은데, 대충 보니 그냥 데이터다. c array에 담겨있는 byte 데이터.


그럼, 사용법을 간단히 보자.


UserDefault 는 싱글톤이다.


사용할려면 우선 그녀석의 인스턴스를 가져와야 한다. 그 위에 붙여서 원하는 함수를 사용하면 된다.


float 값을 저장하고 가져오는 방법만 살펴보자. 나머지는 데이터타입만 바꾸면 모든게 같다.


게임 중에 float score 에다 점수를 저장한다고 가정하자.


float score;

// 게임중에 어째어째 score 에 1234가 저장되었다고 치자.

score = 1234;


// "high score"라는 이름으로 score, 즉 1234를 저장해두자.

UserDefault::getInstance()->setFloatForKey("high score", score);


// 나중에 저장해뒀던 값을 다시 꺼내온다.

float highScore;

highScore = UserDefault::getInstance()->getFloatForKey("high score");

// highScore 에는 1234 가 들어가 있게 된다.



다른 데이터 타입은 빨간 색으로 표시된 부분만 해당 데이터 타입으로 바뀌면 된다.



함수 중에 flush() 가 보이는데, 설명에는 데이터를 xml 에다 저장을 한다고 한다.

flush() 호출하지 않아도 저장이 잘 되는 걸로 봐서, 이건 다른 용도가 있나보다. UserDefault 에 저장된 값들을 별도의 xml 파일로 만들어주는가????


추가 : 안드로이드에서는 값을 세팅한 후에 flush() 를 해야 저장이 되나 봅니다. 안드로이드 개발하시는 분들은 확인해보세요. 저는 아이폰이라 테스트도 못 해 봐서 뭐라 확실하게 말씀드리지는 못 하겠습니다.










Posted by 똑똑한 영장류

레이어를 포함하고 있는 게임의 한 장면, Scene이다.


이 Scene 을 변경할때는 우선 Scene을 만들고 나서 감독에게 바꾸라고 시키면 된다.


Scene* s = PlayLayer::createScene();


Director::getInstance()->replaceScene(s);


위와 같이 간단하게 할 수 있다.


replaceScene 외에 pushScene() 과 popScene()이 있다.


현재 Scene위에 하나 올리는게 pushScene(s), 올려놓은거 치워버리는게 popScene()이다.



이거면 장면의 전환은 맘대로 할 수 있다.


문제는 휙휙 바뀌어서 너무 단순해 보인다는거다...


그래서 준비된게 Transition이다. 장면이 전환될 때 효과를 줄 수 있다.



cocos2d-x.org 사이트에 가면 확인할 수 있는데, 종류가 참 많다.


http://www.cocos2d-x.org/reference/native-cpp/V3.0beta2/da/d00/group__transition.html




각각의 경우에 따라서 create함수의 인자만 달라지지 사용하는 방법은 같다고 봐도 된다.



Scene* s = PlayLayer::createScene();

TransitionFade* fade = TransitionFade::create(1.0f, s, Color3B::WHITE);

Director::getInstance()->replaceScene(fade);


대략 이런 형태에서 벗어나지 않을것이다.






Posted by 똑똑한 영장류

레이블이라고 읽을지, 라벨이라고 읽을지... 본토 발음은 레이블이라 레이블로 표기하기로 한다.



주로 텍스트를 표시하기 좋은 아이템으로 매뉴얼을 살펴보면 세 가지가 있다.


LabelTTF, LabelBMFont, LabelAtlas



LabelTTF


트루타입폰트를 이용해서 텍스트를 찍어줄 수 있으며 기본적으로 아래의 형태로 이용할 수 있다.


LabelTTF* pLabel = LabelTTF::create("ABC", "Hevetica", 32);

pLabel->setPosition( Point( 100, 100) );

pLabel->setColor( Color3B( 255, 255, 0) );

this->addChild(pLabel);


근데, 아이폰에는 있고, 안드로이드에는 없는 폰트라면, 혹은 그 반대라면 제대로 원하는 글씨가 나올수가 없기 때문에 사용하고자 하는 폰트를 프로젝트에 추가를 해서 사용하는 것이 좋다.



LabelBMFont


비트맵 폰트를 이용해서 출력하게 되는데, 이때 *.fnt 파일과 이 파일과 관련된 이미지 파일이 쌍으로 필요하다.

cocos2d-x 3.0 beta2 를 압축해제한 디렉토리에서 \cocos2d-x-3.0beta2\cocos2d-x-3.0beta2\samples\Cpp\TestCpp\Resources\Images 디렉토리를 찾아가서 보면 다음 두개의 파일을 찾을 수 있다.


bitmapFontTest3.fnt

bitmapFontTest3.png


fnt 파일은 아스키파일인데 문서편집기에서 쉽게 열어볼 수 있다. 처음 부분만 살펴보니 아래와 같다.


info face="ActionJackson" size=28 bold=0 italic=0 charset="" unicode=0 stretchH=100 smooth=1 aa=1 padding=0,0,0,0 spacing=1,1
common lineHeight=30 base=26 scaleW=512 scaleH=512 pages=1 packed=0
page id=0 file="bitmapFontTest3.png"
chars count=94
char id=32   x=0     y=0     width=0     height=0     xoffset=0     yoffset=24    xadvance=23     page=0  chnl=0
char id=114   x=0     y=0     width=16     height=25     xoffset=0     yoffset=1    xadvance=14     page=0  chnl=0
char id=82   x=16     y=0     width=16     height=25     xoffset=0     yoffset=1    xadvance=14     page=0  chnl=0
char id=62   x=32     y=0     width=9     height=24     xoffset=0     yoffset=2    xadvance=7     page=0  chnl=0
char id=60   x=41     y=0     width=10     height=24     xoffset=0     yoffset=2    xadvance=8     page=0  chnl=0
char id=125   x=51     y=0     width=9     height=24     xoffset=0     yoffset=2    xadvance=7     page=0  chnl=0


빨간색으로 표시한 부분이 한쌍을 이루는 이미지 파일명이다. 이미지 파일을 열어보면 아래처럼 되어있다.






이미지파일에서 특정 글자를 찾기 위한 정보가 fnt 파일에 들어있는거 같다.

어쨋든 이 한쌍의 비트맵 폰트를 이용해서 아래와 같은 방법으로 레이블을 화면에 뿌려줄 수 있다.


auto label1 = LabelBMFont::create("ABCD",  "bitmapFontTest2.fnt");

label1->setPosition( Point( 100, 100) );

this->addChild(label1);



LabelAtlas


atlas 라는 표현은 이미지 쪼가리쪼가리들을 모아져 있는 큰 이미지라고 생각하면 되는데, cocos2d-x 데모를 실행시켰을 때 화면 왼쪽 아래에 보이는 FPS 표시하는 글자들이 들어있는 fps_images.png 도 atlas 이다.

특별히 문자들만 들어있다고 캐릭터맵이라고도 하는 모양이다.


fps_images.png 를 열어보면 아래처럼 생겼다.


마침표, 슬래시, 0, 1, 2, ..., 9 의 글씨가 들어있는 이미지이다.



숫자를 찍기에는 모자람이 없어보인다.


아래처럼 레이블을 만들 수 있다. 


LabelAtlas* pLabel = LabelAtlas::create("12345", "fps_images.png", 16, 24, '.');


함수 인자를 보면,


"12345" 는 출력할 문자열이고,

"fps_images.png" 는 문자들이 이미지형태로 들어있는 파일의 이름이다.

16, 24 는 이미지파일 내에서 글자 하나가 차지하는 가로, 세로의 크기이다. 16x24 의 크기로 마침표, 슬래시, 0, 1, 등등 한글자씩 추출해낼 수 있다고 알려주는거다.


그리고,..... '.'


atlas 이미지에서 한글자씩 추출해 낼 때, 기준위치는 전체 이미지의 왼쪽 아래에서부터 시작된다.

그렇게 16x24 사이즈로 잘라냈을 때, 첫번째 이미지가 나타내는 문자는 '.' 다... 라고 알려주는거다.

첫번째가 마침표라는 걸 알려주는 것만으로 그 다음 두번째 이미지 안에 있는 글자는 아스키코드 테이블 상에서 마침표의 다음 글자, 즉 슬래시라고 알아낼 수 있다.


아스키코드 테이블을 보면,

마침표, 슬래시, 0, 1, 2, ..., 9 는 연속된 값이다. 아스키코드 46, 47, 48 이렇게 연속된다.


LabelAtlas 에게 첫번째가 '.' 이니까, 그 뒤로는 알아서 찾아서 사용하라는 말이다.


"난 게임에서 점수 표시할 때 슬래시를 쓸 필요가 없으니까, 아틀라스 이미지 만들 때, 슬래시는 빼고 마침표, 0,1,2...이렇게 만들어야지!"


한다고 정말 그렇게 만들면, 숫자 0을 출력하라고 시켰을 때, 1이 출력될 것이다.

비록 슬래시를 사용하지 않더라도 그 16x24 의 공간은 비워놔야한다.




아, 그리고, 레이블을 처음 만들 때, 출력할 값을 지정해 주었지만, 게임에서의 점수처럼 계속 값이 바뀌어야 할 때는 pLabel->setString("new string") 하면 되겠다.



추가할 내용이 있어서 추가한다.


LabelTTF 를 사용하기 위해서 외부 트루타입 폰트를 프로젝트에 추가를 해야하는데...


Resouce 디렉토리 아래에 fonts 라고 디렉토리 만들고 그 안에다가 사용할 폰트를 넣어둔다.


그 디렉토리를 Xcode 에 Resouce 그룹 아래에 폴더의 형태로 추가를 한다. 폴더로 추가하면 파란색으로 표시된다.




그리고 Info.plist 에다가 추가한 내용을 더해줘야한다.


맨 아래 Info.plist 가 보인다.




열어서 아래처럼 디렉토리 이름 아래에 폰트 파일 이름을 적어준다.






이제 소스에서 작업해야한다.


static std::string fontList[] =

{

#if ( CC_TARGET_PLATFORM == CC_PLATFORM_IOS )

    "Marker Felt",

    "Vitamin",

#else

    "fonts/Marker Felt.ttf",

    "fonts/VITAMIN_.ttf",

#endif

    

};


iOS 일 경우와 나중을 위한 안드로이드용을 위한 설정을 위처럼 해준다.


요기서 주의 사항!

빨간색으로 표시된 부분을 보자. 저건 폰트 파일 이름이 아니다. 폰트 자체가 가지고 있는 실제 폰트명이다.

폰트 관련 프로그램으로 확인하던지. 맥의 경우는 파인터에서 마우스 오른쪽 버튼 눌러서 "정보가져오기"를 하면 실제 폰트 이름을 확인할 수 있다. 아래에서 "전체 이름" 이라고 적힌 부분의 값을 이용하면 된다.






이제 LabelTTF 는 아래처럼 사용하면 된다.


LabelTTF* lastScoreLabel = LabelTTF::create(strScore, fontList[1].c_str(), 64);

    lastScoreLabel->setAnchorPoint(Point(0.5, 0.5));

    lastScoreLabel->setPosition(winSize.width/2.0, 855.0f);

    this->addChild(lastScoreLabel, 3);


fontList[1] 즉, Vitamin 폰트를 이용해서 레이블을 출력하게 된다.





































Posted by 똑똑한 영장류

레이어에 붙여놓은 스프라이트를 조작하는 방법쯤 되겠다.


원하는 위치에 놓은것부터 옮기기, 회전시키기, 크기를 조정하기 등등 무수한 액션들이 존재한다.


얼마나 많은지는 아래 사이트를 참고하자. 우선 대충 훑어보기를 바란다. 뭐가 있는지 알아서 써먹을 수도 있지..


http://www.cocos2d-x.org/reference/native-cpp/V3.0beta2/dd/d0d/group__actions.html



보고나면 질린다..ㅡ.ㅡ



그래도 정리를 해야하니까...


스프라이트를 조작하는 거라고 했으니까, 대상 스프라이트가 있어야겠지.

Sprite* catSprite = Sprite::create("cat.png");

catSprite->setPosition( Point( 100, 100 ) );

this->addChile(catSprite);



라고 하나 만들어서 레이어에 붙였다고 가정하자.


cocos2d-x 가 제공하는 많은 액션들을 만들어서 저 스프라이트에 적용하는 방법은 아래와 같다.


catSprite->runAction(액션변수명);



runAction 함수를 호출하기 전에 액션을 만들어둬야하는건 당연하다.


대부분의 액션은 ::create() 로 만들수있다.



MoveTo 라는 액션의 경우 아래처럼 만들수 있다.


auto actionTo = MoveTo::create(2, Point( 200, 200));


create 함수내의 값들은 매뉴얼을 참고하면 되겠다. 설명하자면 2초 동안 현재의 좌표에서 (200, 200) 좌표로 이동시키는 액션이다.



아래처럼하면 현재, 초기 위치 (100,100)에 있던 고양이가 2초 걸려서 (200,200) 으로 이동을 한다.


catSprite->runAction(actionTo);


종류가 많아서 질리지 사용하기에는 무지 쉽다.


MoveTo 액션처럼 사용할 수 있는 액션들이 무지 많다. 저렇게 만들어 쓰면 된다.





Sequence


다른 욕심이 생길 수 있다.


여러개의 액션들을 쭈욱~ 이어서 동작시키려면 어떻게 하면 될까?


여러개의 액션이 순차적으로 실행되기를 원할 때 사용하는 것을 Sequence 라는 액션이 있다.

Sequence는 액션 클래스이긴 하지만 스프라이트를 조작하지는 않는다. 단지 다른 액션들을 여러개 묶어줄 수 있다.


auto actionTo1 = MoveTo::create(1, Point( 100, 100));

auto actionTo2 = MoveTo::create(2, Point( 200, 200));

auto seq = Sequence::create(actionTo1, actionTo2, NULL);

catSprite->runAction(seq);


1초만에 (100,100)으로 간 후, 다시 2초 걸려서 (200,200) 으로 이동하는 액션 두개를 묶어서 seq 라는 시퀀스 액션으로 만들었다.

묶어놓은 액션은 순서대로 실행이 된다.


시퀀스로 액션을 묶을 때, 마지막에 NULL 을 넣어줘야한다. 더 묶어줄 거 없다고 알려주는거라 생각하자..ㅎ



Spawn


또 다른 욕심이 생길 수 있다.


순서대로 액션이 이어지는것이 아니라, 2개 이상의 액션이 동시에 일어나도록 하고 싶으면 우째야할까?

고양이가 빙글빙글 회전하면서 어느 좌표로 이동하도록 만들고 싶을 수도 있지않을까?


이를 위한 Spawn 이라는 액션 클래스가 있다.


auto actionTo1 = MoveTo::create(2, Point( 100, 100));

auto rotate1 = RotateTo::create(2, 180);

auto spawn = Spawn::create(actionTo1, rotate1, NULL);

catSprite->runAction(seq);


2초 걸려 (100,100)으로 이동하는 액션과 2초동안 180도 회전하는 액션이 동시에 발생한다. 휘~익 뒤집어 지면서 이동하는것이다.



Repeat , RepeatForever


다른 특이 액션들이 몇 개 있다.


Repeat와 RepeatForever 는 단일 액션이든지, 시퀀스던지, 스폰이던지, 반복시킬 수 있다.



아래처럼 하면 먼저 만들어놓은 seq 액션을 3번 반복한다.

auto rep1 = Repeat::create(seq, 3);

catSprite->runAction(rep1);


물론 아래처럼 하면 무한 반복한다.

auto rep1 = RepeatForever::create(seq);

catSprite->runAction(rep1)



DelayTime


또 하나 독특한 액션, DelayTime 이 있다.


1초 대기한 후에 이동을 시키고 싶으면 이 1초 대기를 DelayTime 을 써서 만들어 줄 수 있다.


auto actionTo1 = MoveTo::create(1, Point( 100, 100));

auto delay1 = DelayTime::create(1);

auto seq = Sequence::create(delay1, actionTo1, NULL);

catSprite->runAction(seq);




Reverse


모든 액션은 그 반대의 액션을 쉽게 가져올 수 있다.


만약 현재 위치에서 (100,100) 만큼 이동했다가 다시 원래 자리로 돌아오기를 바랄 경우, 액션 두개를 만들어도 되지만, 돌아오는 액션은 가는 액션의 반대라고 바로 만들어줄 수가 있다는 거다.


auto actionGo1 = MoveBy::create(1, Point( 100, 100));

auto actionCome1 = actionGo1->reverse();





여기까지의 내용만 알아도 온갖 종류의 액션을 만들어 사용할 수 있을거 같다.



콜백함수



하지만, 여기서 더 필요한 것이 있다. 바로 콜백 함수다.


게임을 개발하다 보니, 액션이 끝난 시점에서 무언가를 실행시키고 싶을 경우가 많이 있다. 콜백함수를 사용하면 아주 유용하다.



"액션이 종료되면 이 함수를 실행해라!" 라고 설정을 하는거다.


위에서 본 시퀀스 예이다.


auto actionTo1 = MoveTo::create(1, Point( 100, 100));

auto actionTo2 = MoveTo::create(2, Point( 200, 200));

auto seq = Sequence::create(actionTo1, actionTo2, NULL);

catSprite->runAction(seq);


actionTo2 까지 실행이 되어 고양이가 (200,200)으로 이동이 완료된 시점에 고양이 소리를 내고 싶다고 가정하자..(예가 좀 그렇지만..뭐..)


auto actionTo1 = MoveTo::create(1, Point( 100, 100));

auto actionTo2 = MoveTo::create(2, Point( 200, 200));

auto cbSound = CallFunc::create( CC_CALLBACK_0(GameLayer::putSound, this) );

auto seq = Sequence::create(actionTo1, actionTo2, cbSound, NULL);

catSprite->runAction(seq);



...


void GameLayer::putSound()

{

    // 소리 출력 코드

}



CallFunc 를 이용해서 콜백함수를 만들고 시퀀스에다가 혹은 스폰에다가 저렇게 추가해주면 된다.


그런데, 콜백함수에 인자를 주고 싶으면 어떻게 해야하나??


스프라이트등 Node를 전달하거나, 추가 값을 전달하고 싶을 경우, 아래처럼 CallFunc를 사용하고,


CallFunc::create( CC_CALLBACK_0(GameLayer::callback1,this)),
CallFunc::create( CC_CALLBACK_0(GameLayer::callback2,this, sprite1)),
CallFunc::create( CC_CALLBACK_0(GameLayer::callback3,this, sprite1, 12345)),


콜백함수의 구현은 아래처럼 하면 되겠다.


void GameLayer::callback1()
{
...
}

void GameLayer::callback2(Node* sender)
{
...
}

void GameLayer::callback3(Node* sender, long data)
{
...
}



CallFuncN 도 있습니다. N이 노드를 의미한다는데, 콜백함수의 첫번째 인자로 액션을 실행하고 있는 자기 자신을 넘겨주는거 같습니다.



아래처럼 콜백함수를 만들어서 시퀀스에다가 끼워넣어주면 되겠죠.


CallFuncN::create( CC_CALLBACK_1(GameLayer::callback, this)), NULL);


실제 함수 구현은 아래의 모양을 하게 됩니다.


void GameLayer::callback(Node* sender )
{

    // sender 는 액션을 실행한 바로 그녀석!

}



CallFunc 랑 좀 헤깔리네요.



이상.






Posted by 똑똑한 영장류


개발자 사이트에 가서 iTune Connect 가서 [Manage your Apps] 가서, 해당 앱으로 간 후,  [Manage iAd App Network] 에서 Enable 부터 시키고 시작하자.


이제 Xcode 로 와서 프로젝트의 Build Phases > Link Binary With Libraries 에 iAd.framework 를 추가하자.



이제 소스를 건드리기!

Portrait 화면에서 iAd 광고창이 아래쪽에서 올라오는 경우이다.



AppController.h 

#import <UIKit/UIKit.h>


#include <iAd/iAd.h>


@class RootViewController;


@interface AppController : NSObject <UIApplicationDelegate, ADBannerViewDelegate> {

    UIWindow *window;

    RootViewController    *viewController;


    // iAd

    ADBannerView *adView;

    bool bannerIsVisible;

    

}


@end



iAd 헤더파일 추가하고 델리게이트 추가하고 관련 변수 두개 만들었다.


AppController.mm

didFinishLaunchingWithOptions 함수 내에 아래의 위치에 빨간색 코드를 작성하자.


[[UIApplication sharedApplication] setStatusBarHidden:true];

    

    // iAd

    adView = [[ADBannerView alloc]initWithFrame:CGRectZero];

    adView.delegate = self;

    [viewController.view addSubview:adView];

    

    self.bannerIsVisible = NO;

    

    CGRect adFrame = adView.frame;

    // 초기 위치, 아래 예는 아이폰 5에서 세로모드(Portrait)시 아래쪽에 숨어있을 경우의 위치값

    adFrame.origin.x = 0;

    adFrame.origin.y = 568;

    adView.frame = adFrame;

    

    //<- iAd



다음은 관련 델리게이트 함수들을 작성하면 되겠다. 


#pragma mark -

#pragma mark iAd Delegate

- (void)bannerViewDidLoadAd:(ADBannerView *)banner

{

    // 표시할 광고를 잘 읽어왔을 경우...


    if (!self.bannerIsVisible)

    {

        [UIView beginAnimations:@"animateAdBannerOn" context:NULL];

        adView.frame = CGRectOffset(adView.frame, 0, -1*banner.frame.size.height);

        [UIView commitAnimations];

        self.bannerIsVisible = YES;

    }

}


- (void)bannerView:(ADBannerView *)banner didFailToReceiveAdWithError:(NSError *)error

{    

    if (self.bannerIsVisible)

    {

        [UIView beginAnimations:@"animateAdBannerOff" context:NULL];

        adView.frame = CGRectOffset(adView.frame, 0, adView.frame.size.height);

        [UIView commitAnimations];

        self.bannerIsVisible = NO;

    }

}


- (BOOL)bannerViewActionShouldBegin:(ADBannerView *)banner willLeaveApplication:(BOOL)willLeave

{

    // banner 클릭했을때

    return YES;

}

- (void)bannerViewActionDidFinish:(ADBannerView *)banner

{

    // 배너클릭하고 돌아왔을때

}

- (void)bannerViewWillLoadAd:(ADBannerView *)banner

{

    // 광고표기되기 직전에 호출

}

-(void) didFailToReceiveAdWithError:(NSError *)error

{

    // 광고 로드 실패

}



@end














Posted by 똑똑한 영장류

iOS용으로 cocos2d-x 3.0 beta2 를 이용해서 게임을 제작하고 있다고 가정.


광고를 달고 싶은데, admob 을 달고 싶을 경우, 아래의 과정을 통해 가능하다.



1. 아직 개발이 완료되어 앱스토어에 올라가지는 않았지만, 광고를 달아주기 위해서 admob 설정를 할 때, 앱의 Apple ID를 알아야할 필요가 있다.


앱 스토어 등록 전에 앱의 아이튠즈 주소를 알고자 한다면,


애플 개발자 사이트에 로그인을 한 후, iTune Connect 에 가서 prepare for upload 까지만 앱등록을 진행해서 개발중인 앱의 Apple ID 를 얻는다.


이후 정식 등록된 후의 주소는 아래와 같은 모양을 하게 된다.


https://itunes.apple.com/app/id123456789?mt=8


이제 admob 쪽으로 가보자.


www.admob.com 가서 adMob 회원가입부터 한다. 이건 머 그냥 가입이니까 검색을 통해서 해결하기 바란다.


[사이트 및 앱] 으로 가서 앱을 추가한 후, 안내해주는 링크를 통해 sdk 를 다운로드 받는다.


히안한게.. 구글개발자 사이트에 sdk가 더 최신이다. 현재 6.8.0이다.

아래 사이트를 이용해도 되겠다.


https://developers.google.com/mobile-ads-sdk/docs/?hl=ko#ios


다운받아서 적당한 곳에 압축을 해제해 두자.


이제 Xcode에서의 작업이다.


작업중인 xcode 프로젝트에 헤더파일들과 libGoogleAdMobAds.a 를 추가한다. 아래 선택한 파일들 모두 추가하면 되겠다.



그리고, Build Phases > Link Binary With Libraries 에 가서 아래 프레임워크들이 포함되어있는지 확인하고 없으면 추가한다.


  • AdSupport
  • AudioToolbox
  • AVFoundation
  • CoreGraphics
  • MessageUI
  • StoreKit
  • SystemConfiguration


Build Settings > Linking 가서

Other Linker Flags 에 -ObjC 를 추가한다.


여기까지 해서 빌드가 오류없이 되어야한다.


이제 소스 작업이다.


AppController.h 

헤더파일 추가해주고 델리게이트를 추가한다. 광고가 뜰 뷰도 멤버 변수로 만들어둔다.


#import <UIKit/UIKit.h>


#import "GADBannerView.h"


@class RootViewController;


@interface AppController : NSObject <UIApplicationDelegate, GADBannerViewDelegate> {

    UIWindow *window;

    RootViewController    *viewController;

    GADBannerView* bannerView_;

}


@end





AppController.mm

didFinishLaunchingWithOptions() 함수 내의 아래쯤에다가 빨간 색으로 표시된 코드를 작성해준다.


[[UIApplication sharedApplication] setStatusBarHidden:true];

    

    //-> admob

    

    bannerView_ = [[GADBannerView alloc] initWithAdSize:kGADAdSizeBanner];

    bannerView_.delegate = self;

    bannerView_.adUnitID = @"YOUR_ID";

    

    bannerView_.rootViewController = viewController;

    [viewController.view addSubview:bannerView_];

    

    GADRequest* adRequest = [GADRequest request];

    [bannerView_ loadRequest:adRequest];

    

    //<- admob


bannerView_adUnitID 부분에 넣을 YOUR_ID 는...


애드몹 사이트에 가서 [사이트 및 앱] 클릭!

추가되어 있는 앱의 이름 아래에 [설정관리] 클릭하면, 게시자 ID 가 보인다. 그 값을 입력해주면 된다.


















Posted by 똑똑한 영장류

게임 중 배경음악을 재생하거나 효과음을 재생하기 위해서 SimpleAudioEngine 을 이용할 수 있다.


사용법은 매우 간단하고 쉽다.


1. #include "SimpleAudioEngine.h" 를 포함한다.


2. 길이가 긴 음악파일이나 효과음 파일들은 재생하는 순간 로드를 해서 재생하면 지연이 생길 수 있으므로 게임이 시작되기 전에 미리 메모리에 읽어둘 필요가 있다.


CocosDenshion::SimpleAudioEngine::getInstance()->preloadBackgroundMusic("bgmusic.wav");

CocosDenshion::SimpleAudioEngine::getInstance()->preloadEffect("good.wav");



원하는 시점에 재생을 시키면 된다.

CocosDenshion::SimpleAudioEngine::getInstance()->playBackgroundMusic("bgmusic.wav", true);

CocosDenshion::SimpleAudioEngine::getInstance()->playEffect("good.wav");


재생을 멈추거나 계속하는 등의 다른 함수들이 더 있다.

직접 매뉴얼을 찾아보면 도움이 될 것이다.



http://www.cocos2d-x.org/reference/native-cpp/V3.0beta2/de/d8f/class_cocos_denshion_1_1_simple_audio_engine.html









Posted by 똑똑한 영장류

버전이 업되어도 Tiled 의 사용방법은 달라지지 않지만, 2.x버전때와는 tmx 를 다루는 cocos2d-x 의 함수나 방법이 달라졌다.

앞서 다른 포스팅이 있지만, 간단히 다시 정리한다.



tiled 로 tmx 파일은 잘 만들었다고 가정하고,


TMXTiledMap *tileMap;


tileMap = TMXTiledMap::create("map.tmx");

this->addChild(tileMap, Z_MAP, TAG_MAP);

Size stageMapSize = tileMap->getContentSize();

log("Content size: %f, %f", stageMapSize.width, stageMapSize.height);


tmx 파일명을 이용해서 오브젝트를 만들고 레이어에 붙이면 된다.


tileMap->getContentSize() 는 픽셀 혹은 포인트로 가로 세로 크기를 리턴한다.

tileMap->getMapSize() 는 가로 세로 타일 수를 리턴한다.


적다보니 괜히 적었다. 예전 포스팅으로 충분할 거 같다.


http://zzaps.tistory.com/162


cocos2d-x 3.0 beta2 에서는 object layer 를 다루는 부분에서 변화가 있어서 추가로 작성한다.



TMXObjectGroup* objects = tileMap->getObjectGroup("Object Layer 1");

// 오브젝트 레이어어에서 Spawn01라고 지정한 속성값 읽어 오기

ValueMap objectSpawn01 = objects->getObject("spawn01");

float x = objectSpawn01["x"].asFloat();

float y = objectSpawn01["y"].asFloat();

    

log("spwan01 : (%f, %f)", x, y);



Tiled 에서 타일맵을 만들면서 오브젝트 레이어를 추가하고 spawn01 이라는 오브젝트를 넣었다면, 위 코드로 spawn01 오브젝트의 좌표를 가져올 수 있다.



오브젝트에 아래처럼 추가로 propertyName 이라는 변수를 만들고 값을 지정해 줬다면....



아래처럼 그 값을 가져올 수 있다.


// new property 에 추가한 값을 가져오는 방법

std::string propertyValue = objectSpawn01["propertyName"].asString();

log("new property : %s", propertyValue.c_str());











Posted by 똑똑한 영장류
앞서 iOS에서 실행되기 위한 기본 코드를 살펴봤다면, 이번에는 cocos2d-x 영역으로 넘어와서 Classes 디렉토리에 있는 파일들을 살펴보겠습니다. 여기부터가 cocos2d-x 관련 내용이라고 할 수 있겠습니다. 

 1. AppDelegate.h, AppDelegate.cpp
#ifndef  _APP_DELEGATE_H_
#define  _APP_DELEGATE_H_

#include "cocos2d.h"

/**
@brief    The cocos2d Application.

The reason for implement as private inheritance is to hide some interface call by Director.
*/
class  AppDelegate : private cocos2d::Application
{
public:
    AppDelegate();
    virtual ~AppDelegate();

    /**
    @brief    Implement Director and Scene init code here.
    @return true    Initialize success, app continue.
    @return false   Initialize failed, app terminate.
    */
    virtual bool applicationDidFinishLaunching();

    /**
    @brief  The function be called when the application enter background
    @param  the pointer of the application
    */
    virtual void applicationDidEnterBackground();

    /**
    @brief  The function be called when the application enter foreground
    @param  the pointer of the application
    */
    virtual void applicationWillEnterForeground();
};

#endif // _APP_DELEGATE_H_
AppDelegate.h  입니다. AppDelegate 클래스는 cocos2d::Application 을 상속받고있습니다. cocos2d-x 의 코어라고 할 수 있겠네요. 생성자, 파괴자가 선언되어 있고, 앱이 론치가 끝났을 때, 백그라운드로 들어갈 때, 백그라운드에서 다시 활성화될 때 실행될 함수가 선언되어 있습니다. AppDelegate.cpp 를 보겠습니다.
#include "AppDelegate.h"
#include "HelloWorldScene.h"

USING_NS_CC;

AppDelegate::AppDelegate() {

}

AppDelegate::~AppDelegate() 
{
}

bool AppDelegate::applicationDidFinishLaunching() {
    // initialize director
    auto director = Director::getInstance();
    auto eglView = EGLView::getInstance();

    director->setOpenGLView(eglView);

    // turn on display FPS
    director->setDisplayStats(true);

    // set FPS. the default value is 1.0/60 if you don't call this
    director->setAnimationInterval(1.0 / 60);

    // create a scene. it's an autorelease object
    auto scene = HelloWorld::createScene();

    // run
    director->runWithScene(scene);

    return true;
}

// This function will be called when the app is inactive. When comes a phone call,it's be invoked too
void AppDelegate::applicationDidEnterBackground() {
    Director::getInstance()->stopAnimation();

    // if you use SimpleAudioEngine, it must be pause
    // SimpleAudioEngine::sharedEngine()->pauseBackgroundMusic();
}

// this function will be called when the app is active again
void AppDelegate::applicationWillEnterForeground() {
    Director::getInstance()->startAnimation();

    // if you use SimpleAudioEngine, it must resume here
    // SimpleAudioEngine::sharedEngine()->resumeBackgroundMusic();
}
생성자와 파괴자는 아무 하는 일 없이 코드만 마련되어 있습니다. 필요에 따라서 코드를 추가하면 되겠습니다. bool AppDelegate::applicationDidFinishLaunching() 함수가 중요합니다. 앱이 시작되어 cocos2d-x 로 넘어오면 어떤 과정을 거쳐 화면에 그려지는지가 보입니다.  
auto director = Director::getInstance();
auto eglView = EGLView::getInstance();

director->setOpenGLView(eglView);
먼저 화면에 그려지는 모든 것을 관할하게 될 Director 를 가져오네요. AppDelegate 가 상속한 cocos2d::Application 이 cocos2d-x 의 모든 것을 관할한다면, 이 Director 는 화면에 그려지는 모든 것을 관할하는 감독이라 보면 될 거 같습니다. 그 다음, openGL 의 뷰를 가져오고, director 에게 그 openGL view 를 사용하라고 설정을 하네요. 이 세 줄은 cocos2d-x Director 에게 openGL 에서 가져온 뷰를 이용해서 그려라고 설정해주는 거라고 간단히 이해하면 되겠습니다.
// turn on display FPS
director->setDisplayStats(true);

// set FPS. the default value is 1.0/60 if you don't call this
director->setAnimationInterval(1.0 / 60);
그 다음은 화면에다가 FPS를 그려라고 director에게 지시하는 내용입니다. false 로 설정하면 화면에 FPS 를 그리지 않습니다. 그 다음은, FPS 를 설정하는 부분입니다. 이렇게 설정을 하지 않을 경우, 기본 값이 1/60 이랍니다. 1초 동안 60번 화면을 갱신하도록 설정되는군요.
// create a scene. it's an autorelease object
auto scene = HelloWorld::createScene();

// run
director->runWithScene(scene);
HelloWorld 클래스로부터 scene 을 얻어와서 director에게 그리라고 설정하는 부분입니다. cocos2d-x 에서 화면을 구성하는 가장 기본되는 요소가 Scene과 Layer 입니다. Scene도, Layer 도 화면 그 자체를 의미하지만, 터치 이벤트를 처리할 수 있는 것은 Layer 입니다. 그리고, Scene 속에 여러개의 Layer 가 포함될 수 있습니다. 더 나가면, Sprite라고 하는 이미지들은 Layer에 포함될 수 있습니다. 화면을 구성하는 큰 틀이 Scene이고 그 안에 포함되는 여러개의 Layer 가 전체 화면을 구성하게 됩니다. void AppDelegate::applicationDidEnterBackground() 함수 안을 보면, 앱이 백그라운드로 들어갈 때, cocos2d-x 의 Director 라는 객체를 통해 stopAnimation()을 호출하는 것이 보입니다. void AppDelegate::applicationWillEnterForeground() 함수 안에는 앱이 다시 활성화될 경우, 역시 Director 객체를 통해 startAnimation()을 호출하는 것이 보입니다. cocos2d-x 의 실행을 멈추고 다시 시작시키는 부분이죠.   여기까지도 상당히 루틴한 내용들이네요. 앱이 실행되어 cocos2d-x 로 권한이 넘어오면 director 가 사용할 view를 설정하고 처음 화면에 보여질 Scene을 director에게 넘겨줄 뿐이네요. 그럼, 데모에 보여졌던 내용은 어디있을까요? 남은 HelloWorldScene  클래스에 구현되어 있습니다. 우리 눈에 보이는 것들은 모두 Layer 에서 이루어집니다.
#ifndef __HELLOWORLD_SCENE_H__
#define __HELLOWORLD_SCENE_H__

#include "cocos2d.h"

class HelloWorld : public cocos2d::Layer
{
public:
    // there's no 'id' in cpp, so we recommend returning the class instance pointer
    static cocos2d::Scene* createScene();

    // Here's a difference. Method 'init' in cocos2d-x returns bool, instead of returning 'id' in cocos2d-iphone
    virtual bool init();  

    // a selector callback
    void menuCloseCallback(Object* pSender);

    // implement the "static create()" method manually
    CREATE_FUNC(HelloWorld);
};

#endif // __HELLOWORLD_SCENE_H__
파일명은 HelloWorldScene.* 이면서 실제 클래스 이름은 HelloWorld 네요. 아까 director에게 화면에 뿌릴 scene을 넘겨주는 부분이 있었는데, 이 HelloWorld 는 Scene을 상속한게 아니고 Layer을 상속했네요. Layer 주제에 어디서 Scene 이 생겼을까요? HelloWorldScene.cpp 에 createScene() 을 살펴보겠습니다.
Scene* HelloWorld::createScene()
{
    // 'scene' is an autorelease object
    auto scene = Scene::create();

    // 'layer' is an autorelease object
    auto layer = HelloWorld::create();

    // add layer as a child to scene
    scene->addChild(layer);

    // return the scene
    return scene;
}
자신은 Layer 이면서 Scene 을 하나 만들고 그 Scene에다가 자기 자신을 포함시키고, 그 Scene 을 director에게 넘겨줬던 거네요. 마치 자기 자신이 택배 박스 안에 들어가서 그 박스를 택배 아저씨에게 "배달해주세요~" 하는거랑 비슷하네요.  director 에게 Scene 을 넘겨주는 방법까지 살펴봤습니다. 그럼, 이제 진짜 우리 눈에 보여질 것들을 담고 있는 부분을 살펴보겠습니다. 모든 것은 Layer에서 이루어집니다. Layer 를 상속한 클래스의 init() 함수에다가 화면에 보여질 것들에 대한 초기화를 합니다.
// on "init" you need to initialize your instance
bool HelloWorld::init()
{
    //////////////////////////////
    // 1. super init first
    if ( !Layer::init() )
    {
        return false;
    }

    Size visibleSize = Director::getInstance()->getVisibleSize();
    Point origin = Director::getInstance()->getVisibleOrigin();

    /////////////////////////////
    // 2. add a menu item with "X" image, which is clicked to quit the program
    //    you may modify it.

    // add a "close" icon to exit the progress. it's an autorelease object
    auto closeItem = MenuItemImage::create(
                                           "CloseNormal.png",
                                           "CloseSelected.png",
                                           CC_CALLBACK_1(HelloWorld::menuCloseCallback, this));

	closeItem->setPosition(Point(origin.x + visibleSize.width - closeItem->getContentSize().width/2 ,
                                origin.y + closeItem->getContentSize().height/2));

    // create menu, it's an autorelease object
    auto menu = Menu::create(closeItem, NULL);
    menu->setPosition(Point::ZERO);
    this->addChild(menu, 1);

    /////////////////////////////
    // 3. add your codes below...

    // add a label shows "Hello World"
    // create and initialize a label

    auto label = LabelTTF::create("Hello World", "Arial", 24);

    // position the label on the center of the screen
    label->setPosition(Point(origin.x + visibleSize.width/2,
                            origin.y + visibleSize.height - label->getContentSize().height));

    // add the label as a child to this layer
    this->addChild(label, 1);

    // add "HelloWorld" splash screen"
    auto sprite = Sprite::create("HelloWorld.png");

    // position the sprite on the center of the screen
    sprite->setPosition(Point(visibleSize.width/2 + origin.x, visibleSize.height/2 + origin.y));

    // add the sprite as a child to this layer
    this->addChild(sprite, 0);

    return true;
}
처음 나오는 super init first 부분은 앞으로 Layer 를 상속한 클래스의 init() 함수에서 반드시 해 주어야하는 부분입니다. 그 아래에 나오는 내용들이 화면에 종료버튼을 붙이고, "Hello World"라고 글자들을 출력하고, 이미지를 화면 가운데에 그려주는 내용들입니다. 데모 화면에서 보였던 것들이 이렇게 구현이 된 것입니다. cocos2d-x 에서 자주 사용되는 세가지가 등장했습니다. Menu, LabelTTF, Sprite 에 관해서는 이후 포스팅을 하겠습니다. 이제 마지막.
void HelloWorld::menuCloseCallback(Object* pSender)
{
    Director::getInstance()->end();

#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
    exit(0);
#endif
}
메뉴를 만들면서 메뉴 아이템을 탭했을 때 실행될 함수를 이렇게 작성을 합니다. 메뉴를 구현하면서 필요한 함수네요.   여기까지, cocos2d-x 3.0 beta 에서 프로젝트를 만들었을 때, 기본적으로 만들어지는 데모 코드에 대한 것들을 간단히 살펴봤습니다. 본격적인 cocos2d-x 에 관한 내용보다는 앱의 시작부터 cocos2d-x 로 넘어가서 화면에 무언가 그려지기 시작하는 그 시작까지의 과정이 어떻게 되는지 큰 흐름을 살펴본 거 같습니다. 앞으로 cocos2d-x 의 개체들을 하나하나 정리해 보겠습니다.  




Posted by 똑똑한 영장류

프로젝트를 만들었을 때 살펴 봤듯이 coco2d-x 는 멀티 플랫폼을 지원합니다. 게임을 만들면 아마도 iOS 용과 Android 용 두 가지로 배포하기를 원할겁니다. 두 가지로 배포가 되더라도 소스 코드는 공유를 하고 각각에 맞게 빌드를 하게 됩니다.

저는 우선 iOS 용을 위해 Xcode로 작업을 완성한 후, Android 용을 위해 다시 고민을 할 생각입니다. 그래서 특별한 말이 없으면 모두 Xcode에서 iOS 를 위한 내용들을 포스팅할 것입니다.

그럼, Xcode로 프로젝트를 열었을 때 보이는 코드들을 살짝 살펴보겠습니다.



위와 같이 소스 코드들이 있습니다.

먼저 ios 폴더아래에 icons 라는 폴더가 있습니다. 그 안에는 앱의 설정 파일인 Info.plist 와 해상도에 따른 앱 아이콘들이 위치하고 있습니다.

실제 이 이미지 파일들이 위치하고 있는 폴더는 프로젝트 디렉토리 아래에 proj.ios_mac/ios/ 입니다.

나중에 앱 아이콘 등 디자인을 하고 나서 덮어쓰기를 해 주게 됩니다.

이미지 파일 외에 소스 파일 중, 우리가 거의 손을 대지 않아도 되는 파일들이 ios 폴더 아래에 있는 다음 파일들입니다.

main.m
Prefix.pch
AppController.h
AppController.mm
RootViewController.h
RootViewController.mm

1. main.m

Objective-C로 작성되어 있으며, 모든 앱의 시작지점입니다. 내부를 살펴보면, AppController 를 호출하는 부분이 보입니다.

2. AppController.h, AppController.mm

Objective-C 와 C++ 로 작성되어 있습니다. application, 즉 앱의 인스턴스를 만들고 앱의 화면, 즉 window와 그 위의 view 를 위한 view controller 를 마련하고 앱이 시작될 경우, 종료될 경우, 백그라운드로 들어갈 경우 등등 각 이벤트에 필요한 함수들이 구현되어있습니다.

살펴보면, Classes 폴더 안에 있는 AppDelegate.h 를 include 하고 있으며,  앞서 말한 각각의 이벤트가 발생할 때  cocos2d-x도 뭔가를 수행할 수 있도록 코드가 작성되어있습니다. cocos2d-x 와의 연결 지점이 바로 이곳입니다.

하나 예를 보면…

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 함수 내에 아래의 코드가 있는 것을 볼 수 있습니다.

cocos2d::Application::getInstance()->run();

앱이 론치가 끝나면, cocos2d::Application이 실행을 시작한다는 것을 알 수 있습니다.

3. RootViewController.h, RootViewController.mm

Objective-C와 C++로 작성되어 있으며, AppController 에서 앱의 인스턴스를 만들 때 필요한 View Controller 를 위한 파일들입니다.

4. Prefix.pch

Foundation 과 UIKit을 위한 Precompiled header 파일입니다.

여기까지는 거의 손을 댈 필요가 없는 부분이며, main에서 AppController 로 넘어오면서 coco2d-x가 뛰어 놀 수 있는 View를 마련하고 있다고 생각하면 될거 같습니다.

 

Classes 폴더 안의 파일들

1. AppDelegate.h, AppDelegate.cpp

cocos2d-x  Application 을 위한 파일입니다. 여기서부터가 cocos2d-x의 영역입니다. 위에서 이야기한 AppController 에서 cocos2d::Application::getInstance()->run(); 이 호출되고 나면 이제 이 클래스의 인스턴스가 모두 관할해서 돌아가게 됩니다.

2. HelloWorldScene.h, HelloWorldScene.cpp

cocos2d-x 의 요소인 Scene 과 Layer 가 구현되어 있습니다. 데모에서 봤던 화면이 이 파일에서 구현되어 있습니다.

AppDelegate와 HelloWorldScene 은 cocos2d-x 코드니까 다음에 더 자세히 살펴보겠습니다.

 

여기까지 cocos2d-x 로 실행이 넘어가기 전까지 iOS 앱의 기본 코드와 cocos2d-x 의 시작부분까지 간략히 살펴봤습니다.





Posted by 똑똑한 영장류