'cocos2d-x'에 해당되는 글 25건

  1. 2014.09.19 [cocos2d-x 3.2] Xcode 6.0.1 과 iOS 8 에서 빌드 및 실행 결과
  2. 2014.05.27 libpng warning: iCCP: known incorrect sRGB profile 해결방법
  3. 2014.05.27 [cocos2d-x 3.1] 다운로드 및 설치
  4. 2013.12.26 [cocos2d-x 3.0 alpha1] Device Orientation 과 launch image
  5. 2013.10.01 [cocos2d-x 3.0 alpha0] 타일맵과 레티나
  6. 2013.10.01 [cocos2d-x 3.0 alpha0] 타일맵 이용하기 - 오브젝트 레이어 사용하기 (3)
  7. 2013.09.30 [cocos2d-x 3.0 alpha0] EventDispatcher (1)
  8. 2013.09.29 [cocos2d-x 3.0 alpha0] alpha0 등장!
  9. 2013.09.23 [cocos2d-x 3.0 pre alpha0] ParallaxNode
  10. 2013.09.11 [cocos2d-x 3.0 pre alpha0] 2.1.5 제거하고 3.0 pre alpha0 로 업그레이드하기
  11. 2013.08.27 [cocos2d-x 2.1.5] CCRect
  12. 2013.08.22 [cocos2d-x 2.1.4] 타일맵 사용시 가는 선이 나타나는 현상 (2)
  13. 2013.08.20 [cocos2d-x 2.1.4] 시작 프로젝트
  14. 2013.08.07 [cocos2d-x 2.1.4] 터치 이벤트 처리하는 방법
  15. 2013.08.06 [cocos2d-x 2.1.4] 아이폰 기기별 launch image 이미지
  16. 2013.08.04 [cocos2d-x 2.1.4] 해상도 대응하기 - 테스트 (1)
  17. 2013.08.04 [cocos2d-x 2.1.4] sprite 붙이기
  18. 2013.08.04 [cocos2d-x 2.1.4] FPS 표시 없애기
  19. 2013.08.04 [cocos2d-x 2.1.4] intro 화면에서 메뉴 화면으로 전환하기
  20. 2013.08.04 [cocos2d-x 2.1.4] 메뉴 만들기
  21. 2013.08.03 [cocos2d-x 2.1.4] CCLabelTTF 에서 TTF (트루타입폰트) 이용하기
  22. 2013.08.03 [cocos2d-x 2.1.4] scene의 기본형과 layer의 기본형
  23. 2013.08.03 [cocos2d-x 2.1.4] 게임 scene 구성
  24. 2013.08.02 [cocos2d-x 2.1.4] 세로 화면 설정하기
  25. 2013.08.01 [cocos2d-x 2.1.4] box2d 프로젝트 기본 구조

Xcode 6.0.1 에서 cocos2d-x 3.2 프로젝트 빌드 테스트 및 iOS 8 실기기 테스트


iOS 8 이 정식 배포되고 그에 맞춰서 Xcode도 6.0.1 로 업그레이드를 했습니다. 제가 가진 아이폰 5도 iOS 8 로 업그레이드를 했습니다.


이전 버전에서 작업하던 cocos2d-x 3.2 프로젝트가 바뀐 환경에서 문제가 발생하지 않을까 궁금해서 간단히 테스트를 했습니다.



그 결과...


box2d 를 포함하고 있는 게임이 별 문제 없이 잘 만들어지고 잘 실행이 되었습니다.

cocos2d-x 홈페이지에도 특별한 콤멘트가 없는 걸로 봐서, 아직까지는 괜찮은 모양입니다.


끝!





Posted by 똑똑한 영장류

cocos2d-x 로 개발을 하다보면...


libpng warning: iCCP: known incorrect sRGB profile


위와 같은 워닝이 뜨는데, png 파일 내에 올바르지 않은 sRGB profile 이라는 넘이 있다는데........... 정확히 뭔지는 모르겠고........

별다른 조치를 취하지 않아도 앱의 실행에 문제가 발생하지는 않았습니다.

하지만... 계속 찜찜하죠..


imagemagick 이라는 툴을 이용해서 해결할 수 있답니다.

ImageMagick 의 본부는 아래 주소입니다.

http://www.imagemagick.org



ImageMagick 을 설치하기 위해서 Xcode 와 Xcode Command Line Tools 가 설치되어 있어야 한답니다.


Xcode 는 설치되어있지만, Command Line Tools 가 설치되어있는지 가물가물...


https://developer.apple.com 에 가서 Command Line Tools 를 검색해서 설치할 수 있습니다.


터미널에서 아래 명령어를 입력해서 바로 설치를 할 수 있다네요.


$ xcode-select --install



[설치] 클릭하면 되겠습니다.





이제 port 를 이용해서 ImageMagick 을 설치할 수 있습니다.


만약, MacPort 가 설치되어 있지 않다면 아래 링크를 참고해서 설치하시면 됩니다.

port 설치


port 가 설치되어있다면, 터미널에서 아래처럼 입력을 합니다.


$ sudo port install ImageMagick


터미널에 진행상황이 한참 동안 주~욱 표시되고 설치가 완료됩니다. 이것저것 많이, 오랫동안 뭔가를 하는게 수상하긴한데...쩝...

암튼...설치 끝!


그럼, 최종 목적! libpng warning 제거하는 방법입니다.

리소스로 사용하고 있는 png 파일들에서 부적절한 profile 을 수정을 하는지..제거를 하는지...


터미널에서 해당 png 파일들이 있는 디렉토리로 찾아가서 아래 명령어를 입력하면 끝!


find . -type f -name "*.png" -exec convert {} -strip {} \;


or 


find . -name "*.png" -print0 | while read -d $'\0' file; do convert "$file" -strip "$file"; done




하지만, 굳이 제거하지 않아도 된다는...





Posted by 똑똑한 영장류

cocos2d-x 3.1


본부 사이트가서 download 페이지가면 쉽게 찾아서 다운로드할 수 있습니다.


http://www.cocos2d-x.org/download


설치는 다운로드받은 cocos2d-x-3.1.zip 을 원하는 곳에 압축 해제를 한 후, 터미널을 하나 열고, 방금 압축해제한 cocos2d-x-3.1 디렉토리 안에 있는 setup.py 스크립트를 한번 실행시켜주면 되겠습니다.


맥환경의 경우, 홈디렉토리에 있는 .bash_profile 내의 COCOS_CONSOLE_ROOT 라는 환경변수의 값을 3.1에 맞춰서 수정을 해 주네요.






Posted by 똑똑한 영장류
TAG cocos2d-x

cocos2d-x 3.0 alpha1 에서 프로젝트를 만들고, Xcode에서 프로젝트를 열고 나서, 필요하면 Device Orientation을 설정해주어야한다.




Landscape Right 로 고정을 하고나서 론치 이미지를 만들 때 방향에 대해서 살짝 고민을 했다.



Landscape Right, Left 의 의미는 가로모드인데, 홈 버튼이 Left에 있느냐, Right 에 있느냐의 의미이다.


위처럼 설정을 하면, 아이폰을 가로로 쥐었을 때, 홈버튼이 오른쪽에 있음을 의미한다.


이때, Default........png. 즉 론치 이미지는 어떻게 만들어야할까?


론치 이미지는 가로세로 크기가 정해져 있다. 


Default.png 320x480

Default@2x.png 640x960

Default-568h@2x.png 640x1136


세로로 길쭉한, 폰을 세웠을 때의 사이즈이다. 가로세로 방향과는 무관하게 이미지를 그대로 출력하는거다.


하지만, 나는 가로모드로 작업을 하고 있으니까, 처음 론치 이미지도 가로로 놓고 올바른 방향으로 표시되도록 하고 싶다.


아이폰5에서 가로모드로 작업하고 있다면, 

포샵에서 640x1136 크기로 이미지를 만들고, 오른쪽이 가로로 놨을 때 위쪽이 되도록 이미지를 만들면 된다.


정리하자면...


Landscape Right : 홈 버튼이 오른쪽에 있는 가로모드 : 론치 이미지 작업은 오른쪽이 위쪽이 되도록 작업


가로로 이미지 작업을 한 후, 오른쪽으로 90도 회전시키면 되는거다.














Posted by 똑똑한 영장류

첫 레티나 작품, 아이폰 4의 경우 해상도가 640x960 이다.


허나, cocos2d-x 를 이용해서 작업할 경우, 윈도우 사이즈를 320x480 으로 설정하고 작업을 할 수 있다.

포인트와 픽셀...어쩌구 하는 이야기들이 있다.

640x480은 픽셀이고 320x480은 포인트다.


그러나, 레티나에서의 깔끔한 화면을 위해서 포인트가 아니라 픽셀에 맞춰서 포인트의 경우보다 더 큰, 가로세로 두배가 되는 크기의 이미지를 사용해야한다.


설명이 어설프지만, 이건 기본적인 해상도 문제의 이야기니까 넘어가고...


tiled 를 이용해서 타일맵을 만들 때는 어떻게 해야할까?


결론은 타일맵의 크기도 아이폰 4 풀화면의 경우, 640x960 으로 해야한다는 것이다.


320x480으로 하면 어떻게 될까?


Map size 가 320x480 이 되도록 설정을 하고, 

타일셋을 불러와서 그렸다.



그랬더니, 아래와 같이 나왔다.


제대로 풀화면이 되려면 아래처럼 해야한다는 거다.

타일맵을 한 화면 가득한 크기로만 해야한다는 법은 없고..


결론은...

map size 는 레티나를 위한 이미지 사이즈를 다루는 것과 같다...는 것이다.


당연한 거??









Posted by 똑똑한 영장류



오브젝트 레이어 사용하기


Tiled 를 이용해서 맵을 구성할 때, 두 가지 레이어를 이용할 수 있다.

타일레이어와 오브젝트 레이어다.


타일 레이어를 이용하면 그저 배경을 만들 수 있다고 한다면,

오브젝트 레이어를 이용하면 맵 위에 나타날 오브젝트들의 속성을 설정함으로써 좀 더 프로그래밍적으로 접근할 수 있다.


일단, 

tiled 를 이용해서 타일맵을 만들고, 타일셋 이미지를 불러와서 타일 레이어에 맵을 그려준다.












다음, 오브젝트 레이어를 만들어보자.


오브젝트 레이어 추가 방법은... 쉽다...

빨간 화살표를 클릭하고 파란 화살표가 가리키는 아이콘을 클릭한다.





Object Layer 1 이라고 새로운 오브젝트 레이어가 생겼다.
이름 부분을 더블클릭하면 이름을 바꿀 수 있다. Objects 라고 바꿔보자..






오브젝트 추가 방법도... 쉽다.


빨간색 화살표가 가리키고 있는 아이콘들은 오브젝트를 만들어 주기 위한 툴이다. 파란색 화살표가 가리키는 아이콘은 만들어진 오브젝트를 선택할 때 사용하는 아이콘이다.





그 중 나는 파란 사각형을 선택한 후, 적당한 곳에 object를 하나 만들었다.


맵 상에 클릭하면 오브젝트가 하나 생기는데, 오른쪽에 Objects 레이어 아래에 이름도 없는 체크 박스가 하나 생긴다.






만들어준 오브젝트에 속성을 설정해 줘야겠다.




이름없는 체크 박스가 있는 부분을 클릭하고, 아래에 화살표가 가리키는 'object properties' 아이콘을 클릭하자.


아래처럼 속성 창이 나타나면, 이름을 정해주고, Position도 원하는대로 수정을 하자.





Position에 들어가는 값은, 픽셀값이 아니라 전체 맵의 가로세로 칸수에 따른 값이다.
참고로, 타일맵은 좌상단이 (0, 0) 이며 x 는 오른쪽으로, y 는 아래로 증가한다.
지금 예에서는 가로 20 타일, 세로 30타일이니, 가운데 아랫부분쯤되는 위치가 되겠다.





여기까지하고 저장한 후, tmx 파일과 타일셋 이미지 파일을 작업중인 프로젝트에 추가해서 테스트!


아래는 TMX 타일맵을 사용하기 위한 기본코드이다.

타일맵 읽어와서 화면에 붙여주는거다.


TMXTileMap* stageMap = TMXTiledMap::create("test.tmx");

    

this->addChild(stageMapZ_MAPTAG_MAP);

Size stageMapSize = stageMap->getContentSize();

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



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

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


그럼, 오브젝트 레이어에 만들어준 오브젝트는 어떻게 사용하나?


사용방법..루틴하다..




TMXObjectGroup* objects = stageMap->getObjectGroup("Objects"); // 오브젝트 레이어의 이름

Dictionary* spawnPosition = objects->getObject("SpawnPosition"); // 오브젝트 중 이름이 'SpawnPosition' 인 녀석

    

int x = ((String*)spawnPosition->objectForKey("x"))->intValue();

int y = ((String*)spawnPosition->objectForKey("y"))->intValue(); // 오브젝트가 기본적으로 가지게 되는 좌표값 가져오기

log("position : ( %d %d )", x, y);


log 로 찍고 있는 값은 어떻게 될까?


오브젝트 속성에서 x = 9, y=22 를 입력했으니, 그 값이 그대로 나올까?


실제 실행시켜보니, 288, 255 가 출력되었다.


저장한 tmx 파일을 편집기로 열어보니 아래처럼 x, y 값이 저장되어있었다.





저 값들은 어떻게 나온걸까?


288 은 속성에서 입력해준 x 값 9 에다가 타일의 가로폭 32 를 곱한 값이다. 타일인덱스? 값이 픽셀값으로 바뀐 거다.

704도 입력한 y 값 22에다가 32를 곱한 값이다.


근데, 실행시켜서 나온 값, 288과 255는 어찌 나온건가?

288 은 같은 값이 나왔으니 그대로 이해하면 되겠다. 그럼, 255는??


타일은 좌상단이 (0,0) 을 가진다고 했다. cocos2d-x 는 좌하단이 (0,0)이다.

현재 타일맵의 세로 크기는 960이다.

상단에서부터 704가 내려온 지점은 하단에서부터는 255가 된다.


좌표계를 알아서 변환한 후, 좌하단 기준 좌표점을 되돌려주는 것으로 보인다.


근데, 또 이상한 점이 있다.


현재 오브젝트의 x 위치는 캡쳐한 이미지를 보면 알 수 있듯이, 전체 맵의 가운데 부근으로 설정했다.

게임에 사용할 화면 사이즈는 320x480 이다.

가운데는 160 부근이 되어야한다. 그 좌표에 찍어야 화면 가운데쯤에 찍히는거다.


근데, 오브젝트를 통해서 가져온 값은 288이다. 320x480 에 찍으면 오른쪽 끝부근이 된다. 가운데가 아닌거다.


(288, 255)는 640x960 맵 사이즈에서의 값인거다.


게임 화면을 320x480 으로 설정했으니, 이 값을 2로 나누어서 사용해야겠다.


레티나, HD 라는것이 여러모로 불편하게 한다.



암튼...

타일맵을 만들 때, 오브젝트 레이어에서 게임 화면에 나타날 캐릭터나 아이템들의 기본 위치를 작성해두고 코드에서는 위처럼 값을 가져와서 스프라이트를 갖다 붙이면 되겠다.







Posted by 똑똑한 영장류
cocos2d-x 3.0 이 pre 를 떼면서 EventDispatcher 가 새로 생겼습니다.

이전에는 touch event 를 사용하기 위해서 Director에 있는 getTouchDispatcher() 를 이용해서 설정을 했었는데요.


Director* pDirector = Director::getInstance();

pDirector->getTouchDispatcher()->addStandardDelegate(this, 0);


alpha0 로 올리고나면, 위 처럼 getTouchDispatcher()에서 에러가 발생합니다.


이녀석이 사라지고 보다 새로운 EventDispatcher가 나타났기 때문입니다. 이녀석은 이전 버전에서 따로 관리되던 이벤트를 하나로 통합했습니다. TouchDispatcher, KeypadDispatcher, KeyboardDispatcher, AccelerometerDispatcher 는 모두 제거되었습니다.


사용방법은 새로운 릴리즈 노트를 참고하면 되겠습니다.


EventDispatcher 


EventDispatcher 라는 통합 관리 하는 녀석이 있고, touch, keyboard, accelerometer 를 위한 listener 를 각각 작성해서 EventDispatcher에다가 붙여주는 모양을 하고 있습니다.


touch event를 위한 코드를 살펴보겠습니다.터치 이벤트의 경우, EventListenerTouch 를 사용합니다.


캬...이거 머지?


 1auto sprite = Sprite::create("file.png");
 2...
 3auto listener = EventListenerTouch::create(Touch::DispatchMode::ONE_BY_ONE);
 4listener->setSwallowTouch(true);
 5listener->onTouchBegan = [](Touch* touch, Event* event) { do_some_thing();  return true;  };
 6listener->onTouchMoved = [](Touch* touch, Event* event) { do_some_thing();  };
 7listener->onTouchEnded = [](Touch* touch, Event* event) { do_some_thing();  };
 8listener->onTouchCancelled = [](Touch* touch, Event* event) { do_some_thing();  };
 9// The priority of the touch listener is based on the draw order of sprite
10EventDispatcher::getInstance()->addEventListenerWithSceneGraphPriority(listener, sprite);
11// Or the priority of the touch listener is a fixed value
12EventDispatcher::getInstance()->addEventListenerWithFixedPriority(listener, 100); // 10

첫째 줄은 스프라이트 만드는거고,


3 : 터치 리스너를 생성시키고

4 : 리스너의 속성을 설정하고, 삼킨다는게 먼 의미??

5,6,7,8: 해당 이벤트별 함수 정

10 : EventDispatcher 에다가 리스터를 추가하는 방법 1

12 : EventDispatcher 에다가 리스터를 추가하는 방법 2


이 과정을 onEnter()에 넣거나 별도의 함수를 만들어서 작성을 해야겠습니다.


void initEvent() 라는 함수만들어서 그 안에다 몽땅 집어넣겠습니다.

그리고, 터치를 시작했을 때의 함수를 작성해 보죠.

리스너 추가는 두 번째 방법으로 하겠습니다. 



void IntroLayer::initEvent()

{

    auto listener = EventListenerTouch::create(Touch::DispatchMode::ONE_BY_ONE);

    listener->setSwallowTouches(true);

    

    listener->onTouchBegan = [](Touch* touch, Event* event) {

        Point touchPoint = touch->getLocation();

        log("Touch began : (%f %f)",touchPoint.x, touchPoint.y);

        return true;

    };

    

    // The priority of the touch listener is based on the draw order of sprite

//    EventDispatcher::getInstance()->addEventListenerWithSceneGraphPriority(listener, this);

    // Or the priority of the touch listener is a fixed value

    EventDispatcher::getInstance()->addEventListenerWithFixedPriority(listener, 100); // 100 is a fixed value

}


레이어 초기화하는 부분에서 initEvent()를 호출해주면 되겠습니다.


이렇게하고 테스트!





흠..머 어찌 됐던, 터치 이벤트를 받는 것이 가능해졌습니다.


근데, onTouchBegan()  함수가 길어지면, 위처럼 구현하는건 무리가 있겠지요??


별도의 함수를 작성하고, 연결만 해 줄 수 있습니다.


onTouchBegan 일때 실행될 함수를 만들어둡시다.


bool IntroLayer::onTouchBegan(Touch* touch, Event* event)

{


}


그리고, listener 설정에서 아래처럼 해주면 되겠습니다.


listener->onTouchBegan = CC_CALLBACK_2(IntroLayer::onTouchBegan, this);


그외 터치이벤트의 함수는 아래 내용을 참고해서 작성하면 되겠습니다.


std::function< bool(Touch*, Event *)> onTouchBegan

std::function< void(Touch*, Event *)> onTouchMoved

std::function< void(Touch*, Event *)> onTouchEnded

std::function< void(Touch*, Event *)> onTouchCancelled

std::function< void(const std::vector< Touch * >&, Event *)> onTouchesBegan

std::function< void(const std::vector< Touch * >&, Event *)> onTouchesMoved

std::function< void(const std::vector< Touch * >&, Event *)> onTouchesEnded

std::function< void(const std::vector< Touch * >&, Event *)> onTouchesCancelled



터치 이벤트는 이정도로 구현이 가능할 거 같네요. 















Posted by 똑똑한 영장류

cocos2d-x 3.0 이 pre alpha0 였는데, 9월 24일날 pre 를 떼고 alpha0 가 등장했습니다.. 소개가 좀 늦었군요.


다운을 받아서 기존 설치된 pre alpha0를 업그레이드를 해야겠습니다.


방법을 살펴볼까요?

pre 버전의 경우, Xcode 에 템플릿 추가 등을 하지 않고, 임의의 디렉토리에 압축을 풀면 바로 사용이 가능했었죠.

아래 링크를 참고하세요.

pre 버전 설치방법



이번에도 마찬가지입니다.

혹시 모르니 이럴 때마다, 기존에 작업하던 프로젝트들은 잘 백업을 해둬야겠습니다.


pre 버전일때, 저는 /Volumes/Data 2/cocos2d-x/projects/ 아래에 프로젝트를 생성시켜서 작업을 해 왔습니다.

작업하던 프로젝트를 열어서 프로젝트에 추가되어 있는 cocos2d-x 관련 파일들의 경로를 확인해봅시다.


이전 작업하던 프로젝트에서 포함시키고 있는 파일의 경로는 위 그림의 빨간 사각형 안을 보다시피, 그냥 압축 해제했던 그 경로 그대로입니다.


만약, 새로운 버전을 다른 곳에 압축을 풀고, 이전 버전으로 작업했던 프로젝트를 그냥 복사해서 projects 디렉토리로 옮겨서 컴파일을 한다면 프로젝트가 참조하고 있는 cocos2d-x 관련 파일들은 어떻게 될까요? 프로젝트는 옮겼는데, 이전 pre alpha0의 파일들을 계속 참조하면 안 되겠죠?


그래서, 잠깐 확인해 봤습니다.

cocos2d-x-3.0alpha0.zip 을 압축해제하고, 그 아래에 이전 버전에서 작업하던 projects 디렉토리를 가져온 후, 작업하던 프로젝트를  열어 봤습니다. 그리고, 위 그림처럼 파일경로를 살펴봤습니다.




오호라~

cocos2d-x-2.0alpha0 의 파일을 가리키는 군요. 첨부터 상대경로로 파일들을 포함시키고 있었나봅니다.

쓸데없는 걱정을 한 것 같아 머쓱합니다. ㅎ



그렇다면, 적당한 곳에 alpha0 를 압축해제하고, 그 안에 이전 projects 디렉토리를 갖다놓으면 된다는 거군요.


혹시 모르니, 

예전 디렉토리도 그냥 두고, cocos2d-x-3.0alpha0 디렉토리에 projects 디렉토리를 옮긴 후 작업하렵니다. 물론 백업은 꼭 해야겠죠.


나중에 별문제 없이 잘 되면, 이전 디렉토리는 삭제하면 되겠습니다.


설치는 큰 문제가 없네요.


release note 를 참고해서 바뀐 내용들을 살펴본 후, 작업하던 소스에도 적용하면 되겠습니다.




그러나! 직접 위 작업을 해 보신 분들은 뭔가 에러가 발견될 겁니다. ㅋ


그건 alpha0 버전이 되면서 이전 버전에 있던 녀석이 사라지고 새로운 녀석이 나타났기 때문입니다.

다음 포스트에서는 새로 등장한 녀석에 대해서 살펴보겠습니다. 






Posted by 똑똑한 영장류

ParallaxNode, 패럴랙스 노드는 간단히 말해, 배경을 스크롤 해주는 클래스이다.


만약, 게임에서 하나의 배경 이미지만 있고, 그걸 스크롤? 또는 이동시킬 필요가 있다면 그냥 스프라이트 하나를 이용해서 이동시켜주면 될것이다.

그럼, 패럴랙스노드가 뻘짓인가??? 아니.. 패럴랙스노드는 여러겹?의 배경이미지를 스크롤시킬 때 그 진가를 발휘한다.

여러개의 배경 이미지를 서로 다른 속도로 스크롤을 해 줄 수 있다.


예를 들어보면....

자동차를 타고 달리면서 차창 밖을 보면, 가까이 있는 사물은 휙휙 빠르게 지나가지만, 멀리 보이는 들판, 산들은 천천히 움직이는 것을 볼 수 있다.

이렇게 배경이 되는 사물들의,  거리 차이때문에 발생하는 이동 속도의 차이를 패럴랙스 노드를 이용해서 구현할 수 있다.


그럼..간단한 코드 쪼가리를 보자.


배경에 붙일 스프라이트들을 준비하고 아래처럼 패럴랙스노드를 준비할 수 있다.


    ParallaxNode* paraNode = ParallaxNode::create();

        

    Sprite* bg1 = Sprite::create("bg-1.png");

    bg1->setAnchorPoint(Point(0,0));


    Sprite* tree1 = Sprite::create("tree-1.png");

    tree1->setAnchorPoint(Point(0,0));

    

    paraNode->addChild(bg1, Z_BG, Point(0.0, 1.0), Point(0,0));    

    paraNode->addChild(tree1, Z_TREE, Point(0.0, 2.0), Point(0,0));

    

    paraNode->setTag(TAG_PARALLAX);

    

    this->addChild(paraNode, Z_BG);


Z_BG 는 배경이미지의 z order 고 Z_TREE는 더 가까운 배경의 z order 다. 당연 가까운 녀석이 더 큰 값을 가져야한다.


빨간 색으로 표시한 1.0과 2.0이 보이지? 

Point 에서 Y 자리에 설정한 건 Y 축 스크롤을 만들고 있기 때문이다.

bg1 이미지는 Y 값이 1.0.. 기본 속도라고 하자. 

tree1은 2.0으로 세팅했는데, 이렇게 하면, (더 가까이 있는) tree1 은 배경, bg1보다 두배 빠르게 스크롤된다.


여기까지는 준비고. 실제 게임로직에서 paraNode를 setPosition으로 변경해주면 설정해준 비율만큼 다르게 이동됨을 확인할 수 있다.


void PlayLayer::update(float dt)

{

   CCNode* paraNode = this->getChildByTag(TAG_PARALLAX);

    paraNode->setPosition(Point(paraNode->getPosition().x,paraNode->getPosition().y-3));

}


위 예는 게임 루프가 업데이트될 때마다 패럴랙스노드를 y축 방향으로 3픽셀씩 아래로 이동시키고 있다. 실제 실행시켜보면, tree 이미지가 배경이미지보다 더 빨리 아래로 이동하는 것을 볼 수 있다.













Posted by 똑똑한 영장류

1. 우선 2.1.5를 삭제해야하는데, 설치되어있는 Xcode 템플릿을 삭제하면 되겠다.


설치되어 있는 위치는 아래와 같다.

/Users/codecodi/Library/Developer/Xcode/Templates/cocos2d-x/


2. 3.0 pre alpha0 설치하기

cocos2d-x.org 가서 다운받아 압축 풀기기

아무데나 풀어도 되지만, 난 아래처럼 압축 풀어준다.

/User/codecodi/cocos2d-x-3.0alpha0-pre/ 

cocos2d-x-3.0alpha0-pre 를 cocos2d-x 라고 이름 변경도 한다.


3. Xcode 뿐 아니라, 멀티플랫폼을 위한 프로젝트 생성하기

터미널에서 위 디렉토리로 이동.

프로젝트 이름이 app007 일 경우, 아래처럼 입력한다.


$ cd /User/codecodi/cocos2d-x/

$ python ./create-multi-platform-projects.py -p app007 -k com.mydomain.app007 -l cpp


/User/codecodi/cocos2d-x/projects/app007 디렉토리 아래에 프로젝트가 생성된다.



이래저래 하면 되겠다.






Posted by 똑똑한 영장류

CCRect 는 사각형 정보를 가질 수 있는 구조체다.



값을 지정해줄 때는 아래처럼 작성할 수 있다.


CCRect testRect;

testRect.setRect(1, 1, 32, 32);


그럼, testRect 가 차지하고 있는 영역의 좌표를 찍어보자.


CCLog("testRect : (%f,%f)-(%f,%f)",testRect.getMinX(),testRect.getMaxY(),testRect.getMaxX(),testRect.getMinY());


testRect : (1.000000,33.000000)-(33.000000,1.000000)


요렇게 나온다.


이건 시작점에 그냥 width, height 를 더해준 값이 된다.


픽셀 갯수를 세어보면, 폭이 32가 아니라 33이라는거다. 이거 문제의 소지가 있다.

알아놔야 헤매지 않을 거다.









Posted by 똑똑한 영장류

cocos2d 초보로서 횡스크롤을 테스트 중이었습니다.

 

Layer init()에다 아래처럼, Tiled 로 작업한 맵을 불러오고

 

CCTMXTiledMap* map = CCTMXTiledMap::create("MapData/map1.tmx");

this->addChild(map,0,MAP_ID);

 

아래처럼 스케쥴 함수를 만들었습니다.

 

this->schedule(schedule_selector(PlayLayer::tick));

 

그리고, tick 함수 내에서 타일맵 전체를 이동을 시켰습니다.

 

void PlayLayer::tick(float dt)

{

    CCNode* mapNode = this->getChildByTag(MAP_ID);

    CCPoint nowPos = mapNode->getPosition();

    CCPoint newPos = ccpAdd(nowPos, ccp(-10,0));

    mapNode->setPosition(newPos);

}

 

타일맵을 이동시키는 방법으로 저는 이렇게 작성을 했습니다.

 

여기서 스케쥴 시간간격을 바꿔보고, 좌표값의 이동값(-10) 을 바꿔가면서 속도감 테스트를 해 봤습니다.

 

시뮬레이터에서는 아무 문제가 없었는데, 기기에서 테스트를 할 경우,

좀 빠르게 이동을 시키자..아래처럼 검은 선들이 나타났다 없어졌다 하더군요.

 




원인과 해법 검색결과 의심드는 부분은 타일 이미지의 사이즈 문제. 짝수로 만들어야한다...는 것이 있었는데요.

확인해보니, 이 예에서는 타일 이미지가 짝수가 맞습니다. (cocos2d-x 패키지에 들어있는 파일이었습니다.) 

해법이 아니었습니다.

 

질문 글을 남겼고, 맥부기 회원 한분이 알려주신 링크에서 힌트를 얻어 다르게 검색을 좀 해봤더니..역시 진리의 '스택오버플로우'에서 해결 방법을 찾았습니다.

 

http://stackoverflow.com/questions/18235751/black-line-between-tiles-on-iphone-but-not-in-simulator

 

적용했더니, 같은 속도에서 아래처럼 검은 선이 보이지 않게 되었습니다. :)





 

해결 방법은

 

libs/cocos2dx/include/ccConfig.h 에 다음 라인에서 1로 세팅하는 것

 

CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL 1

 

 


 



Posted by 똑똑한 영장류


1.

Default.png

Default@2x.png

Default-568h@2x.png


Resources 디렉토리에 만들어넣고, 프로젝트에 추가하기



2.

IntroScene, IntroLayer, MenuScene, MenuLayer, PlayScene, PlayLayer 클래스 생성하고,

기본 코딩하기.


scene.h

#ifndef __app009__IntroScene__

#define __app009__IntroScene__


#include "cocos2d.h"


class IntroScene : public cocos2d::CCScene {

    

public:

    bool init();

    

    CREATE_FUNC(IntroScene);

    

};


#endif /* defined(__app009__IntroScene__) */


scene.cpp

#include "IntroScene.h"

#include "IntroLayer.h"


using namespace cocos2d;


bool IntroScene::init()

{

    if (CCScene::init()) {

        CCLayer* layer = IntroLayer::create();

        this->addChild(layer,1);

        

        return true;

    }

    else {

        return false;

    }

}


layer.h

#ifndef __app009__IntroLayer__

#define __app009__IntroLayer__


#include "cocos2d.h"


class IntroLayer : public cocos2d::CCLayer {

    

public:

    virtual bool init();

    

    CREATE_FUNC(IntroLayer);

    

};


#endif /* defined(__app009__IntroLayer__) */


layer.cpp

#include "IntroLayer.h"


using namespace cocos2d;


bool IntroLayer::init()

{

    if (!CCLayer::init()) {

        return false;

    }

    

    

    

    return true;

}



3.

dataSingleton 클래스 생성하고, 기본 코딩하기


.h

#ifndef __app009__dataSingleton__

#define __app009__dataSingleton__


class dataSingleton{

private:

    

    dataSingleton();

    ~dataSingleton();

public :

    static dataSingleton* getInstance();

    static void releaseInstance();

    

    int x;

    

};


static dataSingleton* sharedData;


#endif /* defined(__app009__dataSingleton__) */


.cpp

#include "dataSingleton.h"


dataSingleton* dataSingleton::getInstance(){

    

    if (!sharedData)

    {

        sharedData = new dataSingleton;

    }

    

    return sharedData;

}


void dataSingleton::releaseInstance(){

    if(sharedData !=NULL) delete sharedData;

}


dataSingleton::dataSingleton(){

    sharedData = NULL;

    x = -1;

}


dataSingleton::~dataSingleton(){

    delete sharedData;

    sharedData = NULL;

}


써먹을때는 해당 Layer.h 에 #include "dataSingleton.h" 해주고, cpp 에서 아래처럼 불러서 이용.

sharedData = dataSingleton::getInstance();



4. 

Resouces 디렉토리 아래에 Fonts, SD, HD 디렉토리 만들고, 프로젝트의 Resources 그룹 안에다 폴더 형태로 추가하기


5.

appDelegate.cpp 수정하기

typedef struct tagResource

{

    cocos2d::CCSize size;

    char directory[100];

}Resource;


static Resource iPhone3Resource  =  { cocos2d::CCSizeMake(480, 320), "SD" };

static Resource iPhone4Resource =  { cocos2d::CCSizeMake(960, 640), "HD"   };

static Resource iPhone5Resource  =  { cocos2d::CCSizeMake(1136, 640), "HD" };


static cocos2d::CCSize designResolutionSize = cocos2d::CCSizeMake(480, 320);




bool AppDelegate::applicationDidFinishLaunching()

{

    // initialize director

    CCDirector *pDirector = CCDirector::sharedDirector();

    CCEGLView* pEGLView = CCEGLView::sharedOpenGLView();

    

    pDirector->setOpenGLView(pEGLView);

    

    // Set the design resolution

    pEGLView->setDesignResolutionSize(designResolutionSize.width, designResolutionSize.height, kResolutionFixedWidth);

    

    CCSize frameSize = pEGLView->getFrameSize();

    CCSize frameSize2 = pDirector->getWinSize();

    

    if (frameSize.height == iPhone5Resource.size.height)

    {

        CCFileUtils::sharedFileUtils()->addSearchPath(iPhone5Resource.directory);

        pDirector->setContentScaleFactor(iPhone5Resource.size.width/designResolutionSize.width);

    }

    else if (frameSize.height == iPhone4Resource.size.height)

    {

        CCFileUtils::sharedFileUtils()->addSearchPath(iPhone4Resource.directory);

        pDirector->setContentScaleFactor(iPhone4Resource.size.height/designResolutionSize.height);

    }

    else if (frameSize.height == iPhone3Resource.size.height)

    {

        CCFileUtils::sharedFileUtils()->addSearchPath(iPhone3Resource.directory);

        pDirector->setContentScaleFactor(iPhone3Resource.size.height/designResolutionSize.height);

    }

    

    CCPoint p = pDirector->getVisibleOrigin();

    CCSize s = pDirector->getVisibleSize();

    

    // turn on display FPS

    pDirector->setDisplayStats(true);


    // set FPS. the default value is 1.0/60 if you don't call this

    pDirector->setAnimationInterval(1.0 / 60);

    

    CCScene* pScene = IntroScene::create();


    // run

    pDirector->runWithScene(pScene);


    return true;

}












Posted by 똑똑한 영장류


지금까지 테스트로 작성한 코드에 따르면, IntroLayer 에서 일정 시간이 지나면, 메뉴 화면으로 자동으로 전환되게 되어있다.

그전에 화면을 터치하면 메뉴 화면으로 전환되도록 작성해보려한다.


이제서야 터치 이벤트가 나온다.


cocos2d-x 에서 터치를 처리할 델리게이트가 두 개가 있다.


standard touch delegate, targeted touch delegate


두개가 비슷한데, 멀티터치를 이용하려면, standard 를 사용해야한단다.


멀티터치를 사용하지 않더라도, standard 를 이용할 수 있으니까, 뭐 standard 로 작성하면 될 거 같다.


introLayer.h 에 아래 내용을 추가해준다.

virtual void registerWithTouchDispatcher(void);

    

void ccTouchesBegan(cocos2d::CCSet* pTouches, cocos2d::CCEvent* event);

void ccTouchesMoved(cocos2d::CCSet* pTouches, cocos2d::CCEvent* event);

void ccTouchesEnded(cocos2d::CCSet* pTouches, cocos2d::CCEvent* event);

void ccTouchesCancelled(cocos2d::CCSet* pTouches, cocos2d::CCEvent* event);


맨 위의 함수는 standard를 이용할지, targeted 를 이용할지를 설정하기 위해서 사용되는 함수이다.

그 아래는 함수명을 보면 알 수 있듯이, 터치가 시작되었을때, 시작된 후 움직이고 있을 때, 손가락 떼서 터치가 끝났을 때, 그리고는 터치 이벤트가 진행중인데, 다른 시스템의 이벤트로 인해서 그 터치가 취소가 되었을 때 실행될 함수들이다.



introLayer.cpp 에 가서 init() 에다가 아래 내용을 작성해야한다. 이 레이어에서 터치 이벤트를 이용할 거라고 알려주는거다.


// touch enable

    this->setTouchEnabled(true);


그 다음, 헤더 파일에 선언해뒀던 함수들을 작성해주면 된다.

void IntroLayer::registerWithTouchDispatcher(void)

{

    CCDirector* pDirector = CCDirector::sharedDirector();

    pDirector->getTouchDispatcher()->addStandardDelegate(this, 0);

}


void IntroLayer::ccTouchesBegan(CCSet* pTouches, CCEvent* event)

{

    CCSetIterator it = pTouches->begin();

    CCTouch* touch = (CCTouch*)(*it);

    CCPoint touchPoint = touch->getLocation();

    

    CCLog("Touch began : (%f %f)",touchPoint.x, touchPoint.y);

}


void IntroLayer::ccTouchesMoved(CCSet* pTouches, CCEvent* event)

{

    CCSetIterator it = pTouches->begin();

    CCTouch* touch = (CCTouch*)(*it);

    CCPoint touchPoint = touch->getLocation();

    

    CCLog("Touch moved : (%f %f)",touchPoint.x, touchPoint.y);

}

void IntroLayer::ccTouchesEnded(CCSet* pTouches, CCEvent* event)

{

    CCSetIterator it = pTouches->begin();

    CCTouch* touch = (CCTouch*)(*it);

    CCPoint touchPoint = touch->getLocation();

    

    CCLog("Touch ended : (%f %f)",touchPoint.x, touchPoint.y);

    

    changeNextScene();

}

void IntroLayer::ccTouchesCancelled(CCSet* pTouches, CCEvent* event)

{

    CCLog("Touch cancelled");

}



난 ccTouchedEnded()  에 화면을 전환하는 코드를 넣었다. 화면에 손가락을 댈 때 전환이 발생하지 않고 땔 때 전환이 발생하는거다. 이건 머 개발자 마음...


changeNextScene() 은 전에 작성했던, MenuScene 으로 전환시키는 코드를 따로 떼서 만든 함수다.


void IntroLayer::changeNextScene()

{

    CCScene* pScene = MenuScene::create();

    

    CCTransitionScene* pTran = CCTransitionFade::create(1.0f, pScene);

    

    CCDirector::sharedDirector()->replaceScene(pTran);

    

}



이거 비슷하게, 함수 인자로 CCScene 을 받도록 만들면 보다 유용하게 이용할 수 있을 거 같다.


흠...

여기까지 하고 나니까... 간단한 게임을 위한 기본 템플릿? 정도가 완성 된거 같다.


이제 필요한 만큼, 각 레이어에 작업을 하면 되겠다.













Posted by 똑똑한 영장류


앱을 실행시켰을 때, 가장 먼저 표시되는 화면, 이미지를 launch image 라고 한다.

아이폰5 사이즈에 맞게 풀화면으로 표시하려면, 640x1136 사이즈의 Default-568h@2x.png 를 준비해서 프로젝트에 추가해놓으면 된다.


아이폰 4를 위해서는 640x320 크기의 Default@2x.png

아이폰 3를 위해서는 320x480 크기의 Default.png 를 사용하면 된다.


3개의 기기에 대응하기 위해서, 위 이미지 3개를 프로젝트 디렉토리에 복사해 넣고, Xcode 에서도 프로젝트에 추가를 해 주면 된다.





Posted by 똑똑한 영장류


기기마다 해상도가 서로 사맛디 아니할쎄...



참고할 것..

http://cocos2d-x.org/projects/cocos2d-x/wiki/Multi_resolution_support


그리고, 나는 테스트해 볼 것..


지금은 아이폰만 살펴 볼 것임.


기기의 픽셀 수

iPhone 3GS : 320x480

iPhone 4 : 640x960 (retina)

iPhone 5 : 640x1136 (retina)



그럼... 앱이 동작 중에 어떻게 기기를 구분할 수 있을까?


CCSize winSize = CCDirector::sharedDirector()->getWinSize();

CCLog("%f : %f",winSize.width, winSize.height);


위 코드를 이용해서 시뮬레이터에서는 어떻게 결과를 보여주는지 먼저 살펴봐야겠다.

AppDelegate.cpp 에 bool AppDelegate::applicationDidFinishLaunching() 함수 내에 적당한 곳에 작성하자.


iOS Simulator 메뉴에 가서 Hardware 가서 Device 를 iPhone 으로 설정해 주자.




그리고나서, Run!!! 하고, 디버그 콘솔을 살펴보면 아래와 같이 나온다.





320x480 이 나온다.






introBGLayer 하나  만들어서, CCLayerColor로 해주고, 흰색으로 초기화를 해 놓은 상태다. 그 위에 이 라벨들이 올라가는 introLayer 가 있다.


이제 Device 를 iPhone Retina 3.5-inch 로 바꾸고 다시 해 보자. 이게 iPhone 4를 의미한다.






640x960 이다. 확실히 getWinSize() 는 기기의 해상도를 구해준다.





Device를 iPhone 4 -inch 를 선택하고 다시 해보자.

헐~~






640x960 으로 나오고 화면은 아래 그림처럼 아래/위로 잘려나갔다.





이 무슨...???


cocos2d 가 iPhone 5 를 못 알아먹는다???


지금 테스트에 사용하는 샘플 프로젝트에서는 해상도를 위한 아무런 작업을 하지 않은 상태다.

cocos2d 프로젝트 생성에서 제공하는 그대로라는 뜻이다.



요기 보이는 것처럼, 컴파일한 후 보여지는 경고에 Defalut-568h@2x.png 가 없다고 나오는데..이것도 그냥 둔 상태다.


이걸 해결해주면 어떻게 될까??

이 경고 메세지 부분을 클릭하면, Xcode 가 Defalut-568h@2x.png 를 추가해 줄지를 묻는다.

Add 를 눌러 추가해보자.


그리고, 다시 Run!!!

오호라~~





640x1136 이 나오고, 화면도 아래처럼 꽉차게 나온다.





Defalut-568h@2x.png 파일이 프로젝트 내에 존재해야 iPhone 5 해상도를 인식할 수 있는가 보다. 중요!!



근데, 캡쳐한 화면 보면, 뭔가 이상하다. 난 메뉴가 가운데에 위치하도록 코딩을 해줬는데, iPhone 4와 5 에서는 왼쪽 하단 쪽에 위치하고 있다. 글자도 쪼매나군.. 


여기까지는 머...  Defalut-568h@2x.png 이 중요하다는것 정도로 정리하고..ㅋㅋ



이제..cocos2d-x 사이트에서 이야기하는 대응방법을 살펴봐야겠다.


v 2.0.4 부터 enableRetina 메소드 관련 코드들은 제거되었고, 기기가 레티나면 자동으로 활성화가 된단다.

CCEGLView::sharedOpenGLView()->getFrameSize() 를 이용해서 실제 기기의 해상도를 구할 수 있단다.


앞선 테스트에서 사용했던 getWinSize() 는, 좀 더 정확히 이야기하면, 기기의 해상도가 아니고, cocos2d 가 이용할 수 있는 영역을 구해주는거다.


iPhone 3GS 에서는 기기 화면의 한 픽셀이 게임에서 취급하는 좌표상의 한점과 같아서 고민거리가 없었는데, 레티나가 등장하면서 기기 화면의 한 픽셀이 게임에서 취급하는 하나의 좌표점과 1대1 대응이 되지않아 개발자들에게 불편함을 가져왔었지... 

게임상에서 이용하는 하나의 좌표점을 포인트라고 하면, 3GS 는 픽셀과 포인트가 동일한 거고, 레티나에서는 4개의 픽셀이 하나의 포인트가 되는 거다. 그래서 iPhone 4 에서 이쁘게 그려낼려면, 3GS 에서 사용된 이미지보다 가로, 세로 2배씩 크기가 더 커져야되는거다.


그래서, cocos2d 에서는 이걸 어떻게 해결하고 있나..보니...


One is designResolutionSize, another is contentScaleFactor.



모든 기기에서 같은 해상도의 게임화면을 위해서 DesignResolution Size 라는 개념을 이용하고 있다.

게임의 가상공간은 이 사이즈 내에서 돌아가는거라고 생각하면 될거 같다. 설정을 하게 되면, getWinSize()로 구해지는 크기가 이 값과 같다.


그럼, 3GS때부터 내려온, 320x480 포인트 영역 내를 게임공간으로 하겠다고 결정했으면, 다른 기기에서도 그 게임을 위해 320x480의 공간만 잘 주어지면, 리소스의 수정없이 동일한 화면을 볼 수 있을거라는 거다. 그럴사하지? 


그리고, 또....각 기기별 해상도에 따라서, 정확히 말하면, 3GS에서 사용될 일반 이미지와 레티나에서 사용될 고화질 이미지를 구분해서 별도의 디렉토리에 넣어두고, 해당 경우에 따라서 적합한 디렉토리의 이미지들을 로딩해서 사용하도록 할 수 있는데, 이미지를 검색할 디렉토리를 설정하기 위해 setSearchPath() 가 사용된다.

일반 이미지와 고화질 이미지로 구분하면 되겠다. 


그리고, 기기의 해상도 범위 내에, 이미지를 제대로 된 비율과 크기로 출력하기 위해서 스케일팩터를 설정할 수 있는데, 이때, setContentScaleFactor() 라는 함수가 사용된다.


말이 어렵네...


어쨌든, 이게 대략 참고사이트에서 이야기하고 있는 전체적인 원리이고... 실제 코드를 살펴봐야겠다.


일단 참고 사이트의 코드부터..


typedef struct tagResource

{

    cocos2d::CCSize size;

    char directory[100];

}Resource;


static Resource smallResource  =  { cocos2d::CCSizeMake(480320),   "iphone" };

static Resource mediumResource =  { cocos2d::CCSizeMake(1024768),  "ipad"   };

static Resource largeResource  =  { cocos2d::CCSizeMake(20481536), "ipadhd" };


static cocos2d::CCSize designResolutionSize = cocos2d::CCSizeMake(480320);


Resource 라는 구조체는 기기별 해상도와 해당 리소스가 들어가 있는 디렉토리 이름을 저장하기 위한 것이다. 구조체 정의 아래에 small, medium, large 로 나눠서 서로다른 해상도의 기기들을 정의해놓고 있다.


맨 아래에 designResolutionSize 는 게임의 가로,세로 해상도를 설정한 것이다. 게임에서 한 화면의 좌표가 저 사이즈 내에서 이루어진다는거다. 내 게임의 화면 크기는 이거야! 라고 설정해두는거다.

이 코드는 AppDelegate.cpp 의 상단에 위치시키면 되겠다.


그리고, 이젠 이걸 cocos2d 에게 알려줘야한다.


AppDelegate::applicationDidFinishLaunching() 함수 내에서 아래와 같이 작성한다.


CCDirector* pDirector = CCDirector::sharedDirector();

CCEGLView* pEGLView = CCEGLView::sharedOpenGLView();


pDirector->setOpenGLView(pEGLView);


// Set the design resolution

pEGLView->setDesignResolutionSize(designResolutionSize.width, designResolutionSize.height, kResolutionNoBorder);


OpenGL 뷰의 크기를 원하는 해상도 설정하고 있다.


아래는 기기의 해상도를 얻어와서 그에 맞춰서 리소스가 있는 디렉토리를 설정해주는 거다.


CCSize frameSize = pEGLView->getFrameSize();

    

    // In this demo, we select resource according to the frame's height.

    // If the resource size is different from design resolution size, you need to set contentScaleFactor.

    // We use the ratio of resource's height to the height of design resolution,

    // this can make sure that the resource's height could fit for the height of design resolution.

    

    // if the frame's height is larger than the height of medium resource size, select large resource.

    if (frameSize.height > mediumResource.size.height)

    {

        CCFileUtils::sharedFileUtils()->addSearchPath(largeResource.directory);

        pDirector->setContentScaleFactor(largeResource.size.height/designResolutionSize.height);

    }

    // if the frame's height is larger than the height of small resource size, select medium resource.

    else if (frameSize.height > smallResource.size.height)

    {

        CCFileUtils::sharedFileUtils()->addSearchPath(mediumResource.directory);

        pDirector->setContentScaleFactor(mediumResource.size.height/designResolutionSize.height);

    }

    // if the frame's height is smaller than the height of medium resource size, select small resource.

    else

    {

        CCFileUtils::sharedFileUtils()->addSearchPath(smallResource.directory);

        pDirector->setContentScaleFactor(smallResource.size.height/designResolutionSize.height);

    }


빨간색으로 표시한 내용은 실제 사이트의 코드와 다른데, 최근 버전에서 맞춰 수정했다.


그 다음에 나오는 setContentScaleFactor()는 리소스의 크기와 designResolution 으로 설정해준 값과의 비를 입력받고있다.


if, else 로 분기하는 이 부분은 내가 지원하고자 하는 기기에 맞춰서 작성해주면 되겠다.


먼가 많이 헤깔리고 복잡한데.. 




테스트 간다.!


아이폰 대응을 위한, 샘플 프로젝트에 맞춰 기기해상도 설정부분을 수정했다.

static Resource iPhone3Resource  =  { cocos2d::CCSizeMake(320, 480), "iPhone3" };

static Resource iPhone4Resource =  { cocos2d::CCSizeMake(640, 960), "iPhone4"   };

static Resource iPhone5Resource  =  { cocos2d::CCSizeMake(640, 1136), "iPhone5" };


static cocos2d::CCSize designResolutionSize = cocos2d::CCSizeMake(320, 480);


그리고, 나머지 소스부분도 이에 맞춰 수정했다.

bool AppDelegate::applicationDidFinishLaunching()

{

    // initialize director

    CCDirector* pDirector = CCDirector::sharedDirector();

    CCEGLView* pEGLView = CCEGLView::sharedOpenGLView();

    

    pDirector->setOpenGLView(pEGLView);

    

    // Set the design resolution

    pEGLView->setDesignResolutionSize(designResolutionSize.width, designResolutionSize.height, kResolutionNoBorder);


    CCSize frameSize = pEGLView->getFrameSize();

    CCSize frameSize2 = pDirector->getWinSize();

    

    CCLog("%fx%f : %fx%f",frameSize.width, frameSize.height,frameSize2.width, frameSize2.height);

    

    if (frameSize.height == iPhone5Resource.size.height)

    {

        CCLog("5");

        CCFileUtils::sharedFileUtils()->addSearchPath(iPhone5Resource.directory);

        pDirector->setContentScaleFactor(iPhone5Resource.size.height/designResolutionSize.height);

    }

    else if (frameSize.height == iPhone4Resource.size.height)

    {

        CCLog("4");

        CCFileUtils::sharedFileUtils()->addSearchPath(iPhone4Resource.directory);

        pDirector->setContentScaleFactor(iPhone4Resource.size.height/designResolutionSize.height);

    }

    else if (frameSize.height == iPhone3Resource.size.height)

    {

        CCLog("3");

        CCFileUtils::sharedFileUtils()->addSearchPath(iPhone3Resource.directory);

        pDirector->setContentScaleFactor(iPhone3Resource.size.height/designResolutionSize.height);

    }



Finder에서 Resources 디렉토리 아래에 iPhone3, iPhone4, iPhone5 디렉토리를 만들고, Xcode 의 Resources 아래에 드랙&드랍해서 폴더 형태로 추가를 해 준다.


이렇게 하고, 다시 Device 들을 바꿔가면서 테스트를 했다.





호~ 사용된 것은 CCLabelTTF 뿐이지만, 같은 크기로 설정한 글씨가 제대로 보인다.


아래 코드로 FrameSize와 WinSize 를 출력해봤는데, FrameSize가 실제 기기의 해상도이고, WinSize는 setDesignResolutionSize() 함수를 이용해서 설정해준 320x480 이 출력되었다. 차이가 있음을 알아둬야겠다.


CCSize frameSize = pEGLView->getFrameSize();

CCSize frameSize2 = pDirector->getWinSize();

    

CCLog("%fx%f : %fx%f",frameSize.width, frameSize.height,frameSize2.width, frameSize2.height);




오케이..

근데, iPhone 5 가 먼가 의심스럽다. 3GS와 4 는 320x480 과 가로세로 비율이 맞아서 ㄱ저 화면 전체가 320x480 으로 잡혀있는건가??? 4보다 세로로 조금 더 긴데....세로방향으로 늘어난 형태인가??? 지금 상태로는 명확히 확인이 안 된다.

그래서, 캡쳐해서 이미지를 겹쳐봤다.



3GS 위에 4를 겹치니 완전 똑같다.



3GS위에 5를 겹치니 이런 꼬라지다. 가로 세로 모두 늘어난거 같다.



다른 스프라이트를 이용해서 다시 테스트를 해봐야겠다.


iPhone3,4,5 디렉토리안에 각 기기 해상도별 이미지를 만들어서 넣어준다. 


intro.png 는 기기별 해상도 크기와 같은 크기의 이미지다. 화면 전체를 채우는 것을 확인할 때 써먹을라고 넣어뒀다.

iPhone3 에는 320x480, iPhone4 에는 640x960. iPhone5에는 649x1136 의 이미지를 만들어 넣어줬다.


red_square.png 는 일반 화면과 레티나 화면에 적용될 이미지를 테스트하기 위해 만들었다.

iPhone3 에는 100x100, iPhone4와 iPhone5에는 200x200 으로 빨간 사각형을 넣어뒀다.






introLayer.cpp 에서 init() 함수 안에 스프라이트 추가 코드를 작성해 준다.


CCDirector* pDirector = CCDirector::sharedDirector();

    CCSize winSize = pDirector->getWinSize();

    

    CCSprite* pSprite = CCSprite::create("intro.png");

    pSprite->setPosition(ccp(winSize.width/2, winSize.height/2));

//    pSprite->setPosition(ccp(0,0));

    pSprite->setAnchorPoint(ccp(0.5, 0.5));

    this->addChild(pSprite);

    

    CCSprite* pSprite2 = CCSprite::create("red_square.png");

//    pSprite2->setPosition(ccp(winSize.width/2, winSize.height/2));

    pSprite2->setPosition(ccp(0,0));

    pSprite2->setAnchorPoint(ccp(0.0, 0.0));

    this->addChild(pSprite2);


이렇게 해놓고, 다시 기기별 테스트!








흠...역시 iPhone 5 가 이상하다.


리소스는 해당 디렉토리에서 잘 가져오는데, 스케일링이 먼가 잘못됐다. 빨간 사각형 찍힌거 보니, (0,0)이 화면 바깥에 있다.

화면이 넓어졌다.. 스크린 밖으로~~~



CCPoint p = pDirector->getVisibleOrigin();

CCSize s = pDirector->getVisibleSize();


CCLog("(%f %f), %fx%f",p.x, p.y, s.width, s.height);


위 코드로 원점과 사이즈를 찍어봤더니, 아래와 같이 나왔다.


Cocos2d: (24.788727 -0.000015), 270.422546x480.000031


눈에 보이는 원점, 그러니까, 화면 왼쪽, 아래 지점은 24,0 쯤 된다고 나온다. 

눈에 보이는 사이즈는 가로가 270, 세로가 480 정도란다. 320 중에서 270만 보이고있는거다.

이 값들은 cocos2d가 인지하는 좌표계이다.


원점이 화면 밖에 있는데... 흠...


그럼..게임 만들면서 중요 이벤트는 눈에 보이는 영역안에서만 발생하도록 프로그래밍을 해야하는건가?????


화면 안에 320x480 영역을 잡을 수 있으면 가장 좋겠네. 아래 위로 잘리는 영역은 큰 이미지 스프라이트를 배경으로 깔아서 전체 화면을 사용하는 것처럼 보이게 만들고...


policy 를 showAll 로 하고, 스케일 팩터를 width 기준으로 바꿨더니, 아래처럼 나왔다.



화면안에 320x480영역이 다 들어가있다. 저 검은색을 어떻게 처리할까?

전체 화면 크기의 이미지를 좌표를 옮겨가면서 저 검은 색을 덮어보려했지만, 저 영역은 cocos2d가 건드릴 수 없는 영역이었다. 덮을 방법이 없음..


policy 를 fixedWidth 라고 설정하니까, 화면 왼쪽 아래가 원점이 되면서 위쪽으로 영역이 더 길어졌으며, 모든 화면에 접근이 가능한 것을 확인했음..


// Set the design resolution

    pEGLView->setDesignResolutionSize(designResolutionSize.width, designResolutionSize.height, kResolutionFixedWidth);


CCSprite* pSprite2 = CCSprite::create("red_square.png");

    pSprite2->setPosition(ccp(0,568));

    pSprite2->setAnchorPoint(ccp(0.0, 1.0));

    this->addChild(pSprite2,2);

    

    CCSprite* pSprite3 = CCSprite::create("red_square.png");

    pSprite3->setPosition(ccp(0,0));

    pSprite3->setAnchorPoint(ccp(0.0, 0.0));

    this->addChild(pSprite3,3);



이 방법도 괜찮은거 같은데? 



아니면, 이 방식을 버리고, iPhone 5 일 경우에는 designResolution을 320x568로 잡아서 써도 될거 같은데...


어떤 방법이 더 좋을까??


진실은 저 너머에~~~~





























































Posted by 똑똑한 영장류

쉬움..



CCSprite* pSprite = CCSprite::create("sprite.png");

pSprite->setPosition(ccp(0,0));

pSprite->setAnchorPoint(ccp(0.0, 0.0));

this->addChild(pSprite);


AnchorPoint는 이미지의 어디를 잡아서 setPosition에 지정한 좌표에다 꽂을것인가...설정하는거다.


가로, 세로 모두 0.0~1.0 사이의 값을 가질 수 있다.


0,0은 왼쪽 아래, 1.1은 오른쪽 위다. 0.5, 0.5 하면 이미지의 가운데를 의미하겠지.



Posted by 똑똑한 영장류


개발하는 동안에는 어느 화면에서 프레임 레이트가 떨어지는지 확인하기 위해서, 화면에 FPS 를 표시하는 것이 좋지만, 화면 캡쳐를 하거나, 개발이 완료되면 불필요한 내용이니까, 없애야할 것이다. 


AppDelegate.cpp 에서 아래 빨간색으로 표시된 부분은 true 에서 false 로 바꾸면 FPS 가 표시되지 않는다.


bool AppDelegate::applicationDidFinishLaunching()

{

    // initialize director

    CCDirector *pDirector = CCDirector::sharedDirector();

    pDirector->setOpenGLView(CCEGLView::sharedOpenGLView());


    // turn on display FPS

    pDirector->setDisplayStats(false);


    // set FPS. the default value is 1.0/60 if you don't call this

    pDirector->setAnimationInterval(1.0 / 60);

    

    CCScene *introScene = IntroScene::create();

    

    // run

    pDirector->runWithScene(introScene);


    return true;

}






Posted by 똑똑한 영장류


샘플로 만들고 있는 프로젝트는


[Intro] - [Menu] - [Play] - [Result] 화면으로 구성하고 있는데...


[Intro] 에다가 TTF 를 이용해서 라벨 붙여봤고, [Menu] 에는 메뉴 두개 붙여봤다.


확인할 때는, 각각의 레이어를 introScene에 붙여서 확인했었다. 그냥 introLayer 에다가 menu 붙이는 연습을 해도 됐는데..ㅡㅡ;



하지만, 이제는 실제 앱의 흐름처럼, 메뉴씬까지 갈 수 있도록 수정을 해보자.


앱을 실행시키면 Intro 화면이 5초동안 보인 후, 자동으로 Menu 화면으로 넘어가도록 만들어보자.


두가지 내용이 필요하다.


5초후 자동... 이건 스케쥴링이 필요하다는거고, 

화면이 넘어갔다는 것은 scene 전환 기능을 이용했다는거다.


스케쥴링


스케쥴을 위한 함수들이 존재한다.

schedule() 과 scheduleOnce() 등등.


schedule() 은 아래처럼 사용된다.


this->schedule(schedule_selector(IntroLayer::introTick), 1.0f);


1초에 한번씩 IntroLayer::introTick 함수가 실행된다.

시간간격을 지정해주지 않으면, 1초에 60번 계속 실행된단다.


내가 필요했던 기능은 단지 5초정도 지연한 후, 화면전환을 실행할 것이라, scheduleOnce()를 사용한다.


introLayer.cpp 에서 init() 

this->scheduleOnce(schedule_selector(IntroLayer::introTick), 5.0f);


introLayer가 로딩된 후, 5초 뒤에 딱 한번 IntroLayer::introTick 함수가 실행된다.

이 함수는 적당한 곳에 아래처럼 작성하면 되겠다.


void IntroLayer::introTick()

{

   

}


introLayer 가 로딩된 후, 5초 뒤에 introTick() 이 실행되도록 준비했다.


그럼, 화면 전환은 어떻게 하나...

화면 전환이라는 건, Scene 이 다른 Scene으로 바뀌는거다.

감독이 시키는대로 바꾸면 되는거다.ㅋ cocos2d-x에서 감독은 CCDirector::sharedDirector() 다. 코드 어느 곳에서는 이렇게 불러다가 쓸 수 있다.


void IntroLayer::introTick()

{

    CCScene* pScene = MenuScene::create();

    

    CCDirector::sharedDirector()->replaceScene(pScene);

}


전환할 scene을 만들어주고, 감독에게 넘겨주면, 감독이 장면을 바꿔치기한다. ㅋ

replaceScene 말고, pushScene, popScene 이 더 있는데, 이 두 함수는 비교적 짧은 시간, 다른 씬을 현재 화면 위에 올렸다가 내릴 때 사용하는게 좋다. 


헌데, 이렇게 하면, 화면이 눈깜짝할 사이에 휙 바뀌어버린다. 먼가 폼나게 전환되지 않는다. 


그래서, cocos2d-x 는 여러가지, 아주 많은 전환 방식들을 제공하는데, 나는 그 중에서,  서서히 어두워지고, 다시 서서히 밝아지면서 화면이 전환되는 CCTransitionFade를 이용했다.

아래 코드처럼, 전환시간을 1초로 주고, 바뀔 scene을 지정해서 CCTransitionScene 을 만든 후, 이것을 감독에게 넘겨주면 된다.


void IntroLayer::introTick()

{

    

    CCScene* pScene = MenuScene::create();

    

    CCTransitionScene* pTran = CCTransitionFade::create(1.0f, pScene);

    

    CCDirector::sharedDirector()->replaceScene(pTran);

}


전환방법이 아주 많아서 모두 테스트하기도 귀찮다. 설명보고 이거다 싶은 것 골라쓰면 되겠다.
















Posted by 똑똑한 영장류


메뉴만드는 방법이 쉽게 제공된다.


루틴한 방법이니 아래 내용만 잘 알면 될거 같다.



MenuLayer.h 에 메뉴를 클릭했을 때, 실행될 함수를 지정해준다.


class MenuLayer : public cocos2d::CCLayer

{

public:

    virtual bool init();

    

    void MenuClicked(CCObject* pSender);

    

    CREATE_FUNC(MenuLayer);

};


MenuLayer.cpp 에서는 init() 내부에서 메뉴를 초기화 해주고, 헤더파일에서 지정한 함수를 작성해주면 되겠다.


bool MenuLayer::init()

{

    //////////////////////////////

    // 1. super init first

    if ( !CCLayer::init() )

    {

        return false;

    }

    

    CCMenuItemFont* item1 = CCMenuItemFont::create("Play", this, menu_selector(MenuLayer::MenuClicked) );

    item1->setColor(ccc3(255, 0, 255));


    CCMenuItemFont* item2 = CCMenuItemFont::create("Set", this, menu_selector(MenuLayer::MenuClicked) );

    

    item2->setColor(ccc3(255, 255, 0));

    

    // set menu item tag

    item1->setTag(1);

    item2->setTag(2);

    

    CCMenu* pMenu = CCMenu::create(item1, item2, NULL);

    pMenu->alignItemsVertically();

    

    this->addChild(pMenu);

    

    return true;

}


void MenuLayer::MenuClicked(CCObject *pSender)

{

    CCMenuItem* pTempItem = (CCMenuItem*)pSender;

    

    int i = pTempItem->getTag();

    

    CCScene* pScene;

    CCTransitionScene* pTran;

    

    switch (i) {

        case 1 :

            // 태그가 1번인 메뉴, Play 가 클릭되었을 때 실행될 내용 작성

            break;

        case 2 :

            // 태그가 2번인 메뉴, Set 이 클릭되었을 때 실행될 내용 작성

            break;            

        default:

            break;

    }

    

    CCLog("%d Menu Clicked\n", i);

}



pMenu->alignItemsVertically() 는 메뉴 아이템을 세로로 알아서 가운데 정렬해준다. 세로 화면 모드일때, 주로 사용하게 될거고.

alignItemsHorizontally() 는 가로 화면 모드일 때, 알아서 가로로 정렬해준다.


메뉴 버튼을 만들 때, 실행될 함수를 지정하는 부분이 있는데, 

CCMenuItemFont* item1 = CCMenuItemFont::create("Play"thismenu_selector(MenuLayer::MenuClicked) );


MenuLayer::MenuClicked 라는 부분이다.


각 메뉴 아이템 별로 다른 함수를 작성할 수도 있지만, 위 코드처럼, 모든 아이템에 같은 함수명을 지정해주고, 그 함수에서 어느 버튼이 눌렸는지 확인한 후, 분기 실행하도록 작성할 수도 있다.


이때, 어느 버튼이 눌렸는지 알기위해, 각 메뉴 아이템에 태그를 설정해주고, 그 태그값을 확인해서 어는 버튼이 눌렸는지 확인할 수 있다.






Posted by 똑똑한 영장류


cocos2d-x 의 장점이 하나의 소스로 iOS 용, Android 용 두 개의 실행파일을 만들어낼 수 있다는건데, 문제는 폰트 사용에서 발생할 수 있다.


CCLabelTTF 을 이용해서 글씨를 화면에 표시할 경우, 폰트를 지정해줄 수 있는데, 이때 한 OS 에 포함된 기본 폰트를 사용할 경우, 다른 OS에서는 그 폰트가 없을 경우, 화면이 엉망이 될 수 있다.


그렇기 때문에, 두 운영체제 모두에서 동작하도록 게임을 만들고자 한다면, 공통된 폰트를 이용해야할 것이다.


그럼, 공통적으로 양쪽에 다 포함되어 있는 폰트가 무엇인지 조사해서 그것만 사용해야할까? 

그 폰트가 맘에 안 들면 우짜나...


그러니, 사용할 폰트 파일을 프로젝트에 포함해서 사용하면 되겠다.


프로젝트 디렉토리 아래에 Resources 라는 디렉토리가 있는데, Finder 에서 그 안에 Fonts 라는 디렉토리를 만들고 사용할 폰트를 그 안에 넣어두자.

Finder 에서 Fonts 디렉토리를 잡아서 드래깅해서, Xcode에 와서 Resources 그룹에다 놓아준다. 이때, 아래처럼 폴더형태로 추가하도록 선택해준다. 제대로 되면,  Resources 아래에 파란색으로 Fonts 라는 디렉토리?가 생기고 그 안에 폰트들을 확인할 수 있다.


아래처럼 선택하라는 말씀~



프로젝트에 폰트를 추가를 했는데, 어떻게 접근해서 사용을 할 수 있을까?


Xcode에게 이런저런 폰트가 추가되었음을 알려주는 것부터 해야겠다.


Resource 그룹안에 있는 Info.plist 를 클릭하면, 오른쪽에 설정되어 있는 내용들이 보인다.

마우스 오른쪽을 눌러서 Add Row 를 하고, 'Fonts provided by application'을 선택해주자.


그 아래에 item0 에 추가한 폰트를 적어주는데, Resources 디렉토리이하 상대경로로 폰트파일이름 으로 적어주어야한다.

Fonts/폰트파일명 의 형태로 아래처럼 적어주자.




더 필요하면, Item1, Item2...계속 추가해서 작성해주면 된다. 난 Captain Podd.ttf 도 추가를 해 줬다.


이 폰트를 이용해서 Intro 화면에 라벨을 추가해서 테스트해보자.


IntroLayer.cpp 


적당한 곳에 아래 코드를 작성하자.


static std::string fontList[] = { "Candice", "Captain Podd" };


그리고,  IntroLayer::init() 안에 아래 코드를 작성하자.


CCLabelTTF* pLabel1 = CCLabelTTF::create("Hello World", fontList[0].c_str(), 32);

pLabel1->setPosition(ccp(160,300));

pLabel1->setColor(ccc3(255, 0, 0));

this->addChild(pLabel1);


fontList[0] 을 지정해줬기 때문에 Candice 폰트를 이용해서 Hello World 가 표시된다.


Info.plist 에서 폰트를 Item0, Item1 입력한 순서와 fontList[] 배열에 지정해주는 순서와는 아무런 관계가 없다.


다른 폰트들과 같이 사용해보니...아래처럼 나온다.














Posted by 똑똑한 영장류

Xcode에서 cocos2d 프로젝트로 생성시키고 나서, 기본적으로 작성되어져 있는 HelloWorldScene.h 와 HelloWorldScene.cpp 를 삭제하고 내 방식대로 scene과 layer를 추가해서 작업을 하게 된다.



이때, scene과 layer의 속 내용을 달라지더라도 기본 뼈대는 동일하게 가져갈 수 있다.


컨트롤 씨~~ 컨트롤 부이~~ 하기 위해서 여기 기록해둔다.


IntroScene.h

#ifndef __INTRO_SCENE_H__

#define __INTRO_SCENE_H__


#include "cocos2d.h"


class IntroScene : public cocos2d::CCScene {

public:

    virtual bool init();


    CREATE_FUNC(IntroScene);


};



#endif /* defined(__INTRO_SCENE_H__) */



IntroScene.cpp

#include "IntroScene.h"

#include "IntroBGLayer.h"


using namespace cocos2d;


bool IntroScene::init()

{

    if( CCScene::init()) {

        IntroBGLayer* layer2 = IntroBGLayer::create();

        this->addChild(layer2,1);

//        layer2->release();

        return true;

    }

    else {

        return false;

    }

}



IntroLayer.h

#ifndef __INTRO_LAYER_H__

#define __INTRO_LAYER_H__


#include "cocos2d.h"


class IntroLayer : public cocos2d::CCLayerColor

{

public:

    virtual bool init();

    

    static cocos2d::CCScene* scene();

    

    CREATE_FUNC(IntroLayer);

};



#endif /* defined(__INTRO_LAYER_H__) */



IntroLayer.cpp

#include "IntroLayer.h"


using namespace cocos2d;


bool IntroLayer::init()

{

    if ( !CCLayerColor::initWithColor( ccc4(255, 255, 255, 255) ) )

    {

        return false;

    }

    return true;

}


scene과 layer의 뼈대소스다. 소스내의 이름은 알아서 수정해서 쓰면된다.


using namespace cocos2d 와 USING_NS_CC 는 같다.


Xcode에서 C++ class 형태로 파일을 추가하면, .h , .cpp 파일이 생성되고, .h 파일에는 클래스 이름에 맞게 #ifndef , #define 부분이 작성되는데...그대로 둬도 되지만, 아름답지 않다고 생각되면 바꾸면 된다. (실제 아름답지 못하다..ㅋㅋ)











Posted by 똑똑한 영장류


여러개의 scene과 layer로 게임은 구성된다.


게임 코딩 전에 전체적인 구성을 한 번 구상해 볼 필요가 있다.


[인트로 화면] - [메뉴 화면] - [게임 화면] - [결과 화면]


가장 단순한 형태가 되겠다.


[인트로 화면] 에서는 회사 로고나, 게임 스토리에 도움을 줄 내용을 보여주면 좋겠고,

[메뉴 화면] 에서는 시작, 설정 등으로 이동할 수 있는 버튼들을 보여주면 되겠다.

[게임 화면] 이 실제 플레이가 이루어지는 화면이다.

[결과 화면] 은 게임 스테이지가 끝이났을 경우, 그 결과를 보여주고, 다음 스테이지로 이동하거나 메뉴 화면으로 이동할 수 있는 버튼을 보여주면 되겠다.


이름 짓기는... 개발자 마음인데...


IntroScene - IntroLayer

MenuScene - MenuLayer

PlayScene - PlayLayer

ResultScene - ResultLayer


각 scene에서 layer 가 더 필요하면 적절한 이름으로 추가해서 사용하면 되겠지.















Posted by 똑똑한 영장류

cocos2d-x 로 프로젝트를 생성하면, 기본적으로 가로 화면으로 설정되어져 있다.


난 세로 화면에서 돌아가는 게임을 만들고 싶은데, 어떻게 하면 좋은가?


RootViewController.mm 에서 아래 내용으로 수정하면 된다.

// For ios6, use supportedInterfaceOrientations & shouldAutorotate instead

- (NSUInteger) supportedInterfaceOrientations{

#ifdef __IPHONE_6_0

//    return UIInterfaceOrientationMaskLandscape; // 가로 화면 

    return UIInterfaceOrientationMaskPortrait; // 세로 화면

#endif

}


참고로 저기에 설정할 수 있는 값들은 아래와 같다. iOS 6.0 이상에서 가능하다.


Constants

UIInterfaceOrientationMaskPortrait

The view controller supports a portrait interface orientation.


UIInterfaceOrientationMaskLandscapeLeft

The view controller supports a landscape-left interface orientation.


UIInterfaceOrientationMaskLandscapeRight

The view controller supports a landscape-right interface orientation.


UIInterfaceOrientationMaskPortraitUpsideDown

The view controller supports an upside-down portrait interface orientation.


UIInterfaceOrientationMaskLandscape

The view controller supports both landscape-left and landscape-right interface orientation.


UIInterfaceOrientationMaskAll

The view controller supports all interface orientations.


UIInterfaceOrientationMaskAllButUpsideDown

The view controller supports all but the upside-down portrait interface orientation.







Posted by 똑똑한 영장류


프로젝트명을 app001 로 했을 경우, app001 프로젝트 아래에 다음 구조로 기본 생성되더라.


app001

    -Resources

        이미지들, iTunesArtwork, Info.plist

    -ios

        AppController.h

        AppController.mm

        RootViewController.h

        RootViewController.mm

        main.m

    -libs

        -cocos2dx

        -CocosDenshion

        -extensions

        -Box2D

        -libwebsockets

    -Classes

        AppDelegate.h

        AppDelegate.cpp

        HelloWorldScene.h

        HelloWorldScene.cpp

    -Supporting Files

        prefix.pch

Frameworks

    *.framework

Products

    app001.app


언어의 특성상 이 소스의 실행시작은 ios 디렉토리 안에 있는 main.m 이다.


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

    

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

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

    [pool release];

    return retVal;

}


UIApplicationMain 함수를 보면, AppController 를 메인으로 실행시킨다.


AppController.h 와 AppController.mm 로 가본다.


이 두가지 변수가 이용된다.

UIWindow *window;

RootViewController    *viewController;


화면을 의미하는 window 가 기본적으로 필요하고, 화면내의 그림 그릴 공간인 view 를 여러개 관리하기 위해 viewController 라는 것이 이용된다.


- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions


이 함수 안을 살펴보면, 


window 만들어 주고, 거기에 viewController 를 붙여주는데, 이 viewController 에게 EAGLView *__glView 라는 OpenGL ES 를 위한 view 를 붙여준다.


결국 cocos2d 는 이 EAGLView 를 이용해서 화면을 그리게 된다.


cocos2d::CCApplication::sharedApplication()->run();


이부분이 cocos2d 에게 모든 걸 맡기고, 실행을 시작하도록 하는 부분이다.


AppController 에서 사용하고 있는 RootViewController 는 RootViewController.h 와 RootViewController.mm 에 작성이 되어있는데, UIViewController 를 상속한 보통의 뷰 컨트롤러이다.


여기까지는 아주 루틴한 부분이다. 앱이 달라져도 그다지 바뀔 내용이 없다.


AppController.mm 에서 그외 함수들에 포함되어 있는 cocos2d 관련 함수들이 보인다.


cocos2d::CCDirector::sharedDirector()->pause();

cocos2d::CCDirector::sharedDirector()->resume();

cocos2d::CCDirector::sharedDirector()->applicationDidEnterBackground();

cocos2d::CCDirector::sharedDirector()->applicationWillEnterForeground();

cocos2d::CCDirector::sharedDirector()->purgeCachedData();


앱의 실행 상태에 따라서 cocos2d 가 해줘야 하는 것들이 있는데, 위 함수들이 그것들이다.

pause()나 resume() 은 cocos2d의 실행을 멈추거나, 다시 실행을 계속하도록 하는 것이다.

그 아래 2개는 각각, 앱이 백그라운드로 들어갔을 때, 다시 포어그라운드로 나올 때, cocos2d 가 특별히 해 줘야할 내용들이다.

마지막 함수는 앱이 메모리 부족 경고를 받았을 때, 캐쉬된 데이터들을 없애주기 위해 사용된다.


cocos2d::CCDirector::sharedDirector()->applicationDidEnterBackground();

cocos2d::CCDirector::sharedDirector()->applicationWillEnterForeground();


이 두가지는 앱의 특성에 따라서 해야할 일들이 달라질 수도 있는데, 개발자가 맘대로 작성을 할 수 있어야 될 것이다.


그 내용이, AppDelegate.h 와 AppDelegate.mm 에 작성되어 있다.


class  AppDelegate : private cocos2d::CCApplication


이렇게 CCApplication을 상속받고 있으며, 아래 3개의 함수가 기본 작성되어 있는데, 필요하다면 내용을 더 추가하면 되겠다.


virtual bool applicationDidFinishLaunching();

virtual void applicationDidEnterBackground();

virtual void applicationWillEnterForeground();


bool AppDelegate::applicationDidFinishLaunching()

{

    // initialize director

    CCDirector *pDirector = CCDirector::sharedDirector();

    pDirector->setOpenGLView(CCEGLView::sharedOpenGLView());


    // turn on display FPS

    pDirector->setDisplayStats(true);


    // set FPS. the default value is 1.0/60 if you don't call this

    pDirector->setAnimationInterval(1.0 / 60);


    // create a scene. it's an autorelease object

    CCScene *pScene = HelloWorld::scene();


    // run

    pDirector->runWithScene(pScene);


    return true;

}


이 코드를 잘보면, cocos2d가 실행되기 위해 준비하고 있는 내용들을 알 수 있다.


앱이 시작되고 나면, cocos2d 는 CCDirector를 초기화하고 화면에 FPS를 표시할 것인지를 설정하고, FPS를 설정하고, 처음 화면에 띄울 Scene을 만들고, 그 Scene을 이용해서 실행을 시작한다.


처음 보여줄 Scene이 HelloWorld 다. 이건 HelloWorldScene.h 와 HelloWorldScene.mm 에 작성되어있다.


프로젝트를 생성하기만 했는데도, 대부분의 루틴한 내용을 기본적으로 잘 작성되어져 있다. 

개발자가 만들어내는 Scene 이 앱의 차이를 만들어낸다.


box2d 프로젝트로 생성을 시키면, 다른 코드의 수정없이, box2d 물리엔진을 이용한 간단한 예제를 실행시켜볼 수 있다. 

예제는 화면을 탭하면, 사각형의 오브젝트가 바닥으로 떨어지는 내용이다.


HelloWorldScene.h 와 HelloWorldScene.mm 은 이어서 제대로 살펴봐야겠다.
















Posted by 똑똑한 영장류