[cocos2d-x] Makeschool 강좌 (3) Xcode를 이용해 코딩하기.

     



지난 포스팅에서 코코스 스튜디오를 통해 화면을 만들었습니다. 그 다음 만든 화면은 Xcode로 publish했지요.


기존에 Xcode상에서 화면을 만들었을때는 객체나 스프라이트를 만드는 것을 일일이 선언했기 때문에 사용하는데 크게 문제가 없었는데, 지금 같이 코코스 스튜디오를 사용해 화면을 만든 경우, Xcode상에는 단순히 .csb파일을 로드한 코드밖에 없습니다. 따라서 화면에 사용된 스프라이트들을 사용하기 위해서는 매칭하는 코드가 있어야 할텐데요... 이번 강좌에 해답이 있을 것 같네요.


일단 지난시간에 publish했던 앱의 소스를 Xcode로 실행합니다. 가장 먼저 손봐야할 부분은 AppDelegate.cpp입니다. 앱의 기본적인 설정을 정하는 파일이죠.




Xcode의 AppDelegate화면입니다. 저는 보통 위처럼 화면을 분할해서 사용하는데, 왼쪽에는 실제 사용하는 코드 페이지를 띄우고 오른쪽은 보조화면입니다. 보통 헤더파일이나 이전 소스페이지가 자동으로 나오죠. 설정하는 방법은 알트 + 커맨드 + 엔터 입니다. 다시 한페이지만 보고싶다면 커맨드 엔터를 누르면 되구요.


가장먼저 수정할 부분은 bool AppDelegate::applicationDidFinishLaunching() 입니다. 메소드 이름을 보면 해당 메소드가 어떤 역할을 하는지 대략적으로 알 수 있습니다. 이 메소드는 앱 실행이 종료되었을 때 실행되는 메소드입니다. 즉 앱이 실행되자마자 실행되는 초기설정을 정하는 곳이라고 할 수 있겠네요.


메소드 안에 보시면 다음과 같은 코드가 있습니다.


director->getOpenGLView()->setDesignResolutionSize(960, 640, ResolutionPolicy::SHOW_ALL);


이 코드는 화면의 크기를 결정해주는 코드입니다. 현재는 해상도 960, 640에 ResolutionPolicy::SHOW_ALL 로 설정되어 있습니다. 이 부분을 다음과 같이 바꿔줍니다.


glview->setDesignResolutionSize(960, 640, ResolutionPolicy::FIXED_HEIGHT);


이렇게 높이를 고정함으로써 폰에서 화면을 고정시킬 수 있습니다.


다음으로 HelloWorldScene.cpp 파일을 수정해야 합니다. 현재 cocos2d-x에 버그가 있어서 화면을 제대로 표시 못할 수 있다고 하는군요. init()안에 다음과 같은 코드가 있는데, 아래 코드를 몇 줄 추가합니다.


auto rootNode = CSLoader::createNode("MainScene.csb");


Size size = Director::getInstance()->getVisibleSize();

rootNode->setContentSize(size);

ui::Helper::doLayout(rootNode);


앞으로 새로운 csb파일을 로드할 때마다 위와같은 코드를 추가해줍니다. 그럼 버그가 없어질거라고 하네요 ^^.

아마 cocos3d-x 3.7.x 버전의 버그이니까 금은 없어졌을 수도 ^^... 하지만 아직 확신할 수 없으니 적어줍니다.


이제 객체를 관리하기 위한 새로은 클래스를 만들어줍니다. 왼쪽 메뉴에서 Classes폴더를 오른쪽 클릭한 다음 New File...을 눌러 새 C++ 클래스를 만듭니다.








경로를 정할때 Target에 Mac(혹은 Desktop)을 체크하는 것을 잊지 맙시다.


먼저 Creture의 헤더파일을 손봐줍니다. 기본적으로 #include<stdio.h> 가 포함되어 있는데, 쓸모 없으니 지우고 다음과 같이 추가합니다.





이게 기본 헤더파일의 형식입니다. public과 protected의 차이점은 잘 알고 계신다고 믿겠습니다 ^^..


이제 public: 아래 다음 코드를 추가합니다.




이 두개는 거의 형식화된 코드인데 cocos에서 클래스를 만들때 항상 입력해주는 습관을 기릅시다. CREATE_FUNC은 매크로인데 create() 메소드를 상속받아 사용할 수 있게 해줍니다. init()의 경우는 create() 메소드를 사용할 때 자동으로 호출되는 함수로 override를 통해 선언해줍니다.


다음으로 init() 밑에 우리가 실제로 사용할 메소드들을 선언해줍니다. 원래 어떤 메소드를 만들지 정의를 하고 메소드 를 선언해야하지만, 우리는 따라하는 입장이니 일단 메소드들을 만들어 놓고 어떻게 돌아가는지 알아봅시다.




두 개의  set과  get메소드를 선언했습니다. 첫번째로 IsAlive는 해당 Creature가 살아있는지를 체크하는 메소드이고, LivingNeighborsCount는 주변에 얼마나 많은 Creature가 살았는지 확인하는 메소드처럼 보이는군요? 이름으로 유추한다면요..


get,set 메소드는 public에 선언하지만 사용되는 내부 변수들은 protected에 선언합니다. 캡슐화의 정석이라고 할까요?




다음으로 클래스파일을 만들어 봅시다. Creature.cpp를 보면 이전까지 우리가 수정하던 헤더파일을 기본적으로 include하고 있습니다. 그 아래 cocos2d의 네임스페이스와 init 메소드를 선언합니다. 




namespace를 선언하는 이유는 cocos2d에서 사용하는 기능들을 사용할 때 항상 앞에 cocos2d:를 붙이는데, namespace로 설정해놓으면 생략이 가능하기 때문입니다. 만약 namespace를 선언하지 않을경우 아래 Sprite를 명시할 때 cocos2d::Sprite::.... 라고 명시해야 합니다.


앞서 헤더파일에서 말씀드린 것처럼 init()메소드는 create()에 의해 자동으로 호출되는 메소드입니다. 쉽게 말하면 초기화 함수죠. Assets/SpriteImages/bubble.png로 스프라이트로 만들어서 실패하면 false를 반환하고, 성공하면 LivingNeighborsCount를 0으로 세팅하고 IsAlive를 false로 선언합니다. 물론 아직 두 메소드를 만들지 않아서 실행되지 않겠죠? 


이제 메소드들을 만들어 봅시다.




객체지향 프로그래밍을 조금 해보신분이면 get과 set메소드를 아주 능숙하게 다루실 겁니다. 이클립스같은 경우 자동으로 get, set메소드를 생성해주는데... 뭐 사실 cocos에도 get과 set을 자동으로 생성해주는 매크로가 있습니다만.. 여기서는 사용안하고 있군요 ^^


아무튼 여기서 주의할점은 setIsAlive에는 this->setVisible(isAlive); 를 넣어야한다는 점입니다. 지금 Creature가 살았는지 죽었는지 설정하는 부분이니까, 그 변수에 맞춰 Creature를 보여줄지 말지를 결정합니다.


이제 Grid 클래스를 만들차례입니다. 코코스에서 바둑판처럼 만든 화면이 있지요? 

이 Grid객체를 커스텀 클래스로 만들어 관리하고 싶다면 어떻게 할까요?


다시 코코스 스튜디오를 열어서 Grid.scd를 수정합니다.




위와 같이  Grid.csd를 열고, 타임라인에서 가장 위에있는 Node를 클릭하면 왼쪽에 Custom Class를 적는 부분이 있습니다. 거기다가 Grid라고 입력하면, Xcode상에서 Grid라는 이름으로 커스텀 클래스를 만들 수 있습니다!! 설정하고 Publish 하는 것을 잊지마세요~!!


자 이제 Xcode로 돌아가서 Grid 클래스를 만들어봅시다. 코코스 스튜디오에 우리는 Grid를 노드로 만들었기 때문에 Creature와 달리 Node를 상속받아 만들어야합니다.




Creature 클래스를 만들었던것과 똑같이 cpp와 hpp를 만들어주고, 위와같이 hpp를 수정합니다. 이름은 Grid.


public에 선언된 것들은 익숙한 것도 있고 새로 만든 것도 있는데, onEnter()의 경우 추가 설정하기위에 자주 쓰이는 메소드이니 기억해줍시다. 다른것들도 어떻게 사용되는지 아직 이름만 가지고는 잘 모르겠군요. 특이한점은 protected에서 Creature를 벡터로 선언해주었다는 것입니다. 벡터는 배열과 비슷한데, 좀더 추가 기능이 있는 배열이라고 생각하시면 됩니다.




자 이제 Grid.cpp를 작성할 차례입니다. 상당히 많은 것을 썻는데, 아직 다 쓴게 아닙니다. 일단 먼저 Grid에 사용되는 열과 행을 상수로 정의합니다. ROWS와 COLUMNS를 const로 정의한게 보이시죠? 그다음 init를 만들고 그아래 onEnter를 만듭니다. 여기서 왜 구지 설정하는 부분을 init와 onEnter로 나뉘는지 궁금하실텐데, init에서 스프라이트가 완전이 로드되지 않았을때 사이즈나 위치를 설정하면 오류가 나기 때문에, 완전히 로드된 뒤에 설정할 것이 있을 때는 onEnter()에서 설정합니다. 


onEnter()에는 setupGrid()와 setupTouchHandling이 있는데 일단 setupGrid()먼저 작성했습니다. setupGrid()의 내용은 creature 배열을 만들고 grid스프라이트 크기를 구해서 각 creature들의 위치를 정해주는 것이죠. 여기서 grid스프라이트는 코코스 스튜디오에서 만들었던 grid 스프라이트입니다. 기존에 포스팅에서 이 부분은 자주 설명했기 때문에 자세한 내용은 생략하겠습니다. 


코코스에서 커스텀 클래스를 선언할 때는 항상 Reader 클래스가 필요합니다. Grid라는 커스텀클래스를 csd에서 불러오기위해 GridReader를 만들어줘야 합니다.




이 코드는 어떤 커스텀 클래스를 불러오는 Reader든지 동일한 코드입니다. 클래스이름만 빼구요. 이제 이 리더를 코코스에서 만든 csd를 불러올 때 사용하도록 등록하는 절차가 남았습니다.




HelloWorldScene.cpp에서 CSLoder를 사용해 코코스 스튜디오에서 만든 화면을 불러온 것이 기억나시나요?

여기서 MainScen.csb를 불러오기 전에 리더를 추가합니다. 이 리더를 추가함으로써 .csb를 읽어올때 아 Grid라는 걸 읽을때는 GridReader를 사용하면 되는구만~ 하고 컴퓨터가 알 수 있습니다.


자 이제 테스트를 해볼까요? Grid.cpp에서 아직 만들지 않은 this->setupTouchHandling()을 주석처리하고, setupGrid() 안에 있는 gridArray.pushBack(creature); 아래 다음코드를 추가합니다.


creature->setVisible(true);


이제 실행버튼을 눌러봅시다.


?! 갑자기 애러가 나네요!...




디버깅을 해보니 위에 위치에서 에러가 났습니다. creature를 제대로 생성하지 못한것 같습니다. 이유를 찾아보니,, creature를 만들때 Asset에 있는 Bubble.png를 사용했는데 이 그림이 없었군요..! 옮겨놓는다는 걸 깜빡했습니다.

초반에 받아놓은 Asset폴더에 있는 Bubble.png를 프로젝트 폴더에 Resource폴더에 Asset, SpriteImages 경로에 넣어주고 다시 실행합니다.




오옷... 원래 없던 Bubble들이 보기좋게 제위치에 들어갔습니다!!

하지만 아직 눌러도 별 반응이 없습니다. 아직 만들지 않은 setupTouchHandling이 아마 터치이벤트를 담당하는 부분인 것 같군요 ^^


터치이벤트 관련 코딩은 다음 포스팅에 적도록 하겠습니다~!

반응형

댓글

Designed by JB FACTORY