coos2d-x 게임 만들기 2편에 이어서 3편에서는 적 스프라이트를 추가해 보고 적 스프라이트가 움직이도록 해 보겠습니다. 적 스프라이트를 화면에 넣는 메서드를 만들고 게임 루프에서 해당 메서드를 주기적으로 호출해서 여러 명의 적이 출현 하도록 만듭니다.
1. 적을 추가하는 메서드 만들기
적을 추가하는 메서드 이름을 addTarget()이라 하겠습니다. GameScene.h 와 GameScene.cpp 파일을 열어 아래와 같이 코드를 추가합니다.
GameScene.h
//: 적 스프라이트를 랜덤 위치와 속도로 화면에 추가합니다. void addTarget();
GameScene.cpp void GameScene::addTarget() { }
이제 addTarget() 함수에 코드를 추가해 보겠습니다. 코드의 설명은 주석을 참고해 주세요.
GameScene.cpp void GameScene::addTarget() { //: 적 스프라이트를 만든다. CCSprite *target = CCSprite::spriteWithFile("Target.png", CCRectMake(0, 0, 27, 40)); //: 적 스프라이트의 Y 좌표를 랜덤으로 하여 위치를 잡는다 CCSize winSize = CCDirector::sharedDirector()->getWinSize(); int minY = target->getContentSize().height/2; int maxY = winSize.height - target->getContentSize().height/2; int rangeY = maxY - minY; int actualY = ( rand() % rangeY ) + minY; target->setPosition( ccp(winSize.width + (target->getContentSize().width/2), actualY) ); this->addChild(target); }
적의 위치의 x좌표는 오른쪽 화면 끝이고 y좌표는 화면 높이에서 랜덤 값을 정하여 스프라이트의 위치를 잡습니다. 이제 적 스프라이트를 움직여 봅시다.
2. 적이 움직이게 메서드 수정하기
적이 움직이게 하기 위해서 CCMove 액션을 사용할 것입니다. 아이폰에서 앱을 작성해 보신 분이면 셀렉터 개념에 익숙할 것입니다. 일종의 함수 포인터인데요.
cocos2d-x는 C++로 만들어져서 SelectorProtocol 클래스를 만들고 해당 클래스의 메서드를 가리키도록 셀렉터를 구현하였습니다. 아래는 SelectorProtocol의 클래스 선언파일입니다.
#ifndef __COCOA_SELECTOR_PROTOCOL_H__ #define __COCOA_SELECTOR_PROTOCOL_H__ #include "ccTypes.h" #include "CCObject.h" namespace cocos2d { class CCNode; class CCEvent; class CC_DLL SelectorProtocol { public: virtual void update(ccTime dt) {CC_UNUSED_PARAM(dt);}; virtual void tick(ccTime dt){CC_UNUSED_PARAM(dt);}; virtual void callfunc(){}; virtual void callfunc(CCNode* pSender){CC_UNUSED_PARAM(pSender);}; virtual void callfunc(CCNode* pSender, void* pData){CC_UNUSED_PARAM(pSender);CC_UNUSED_PARAM(pData);}; virtual void menuHandler(CCObject* pSender){CC_UNUSED_PARAM(pSender);}; virtual void eventHandler(CCEvent* pEvent) {CC_UNUSED_PARAM(pEvent);}; // the child call responding retain/release function virtual void selectorProtocolRetain(void) {}; virtual void selectorProtocolRelease(void) {}; }; class CCNode; typedef void (SelectorProtocol::*SEL_SCHEDULE)(ccTime); typedef void (SelectorProtocol::*SEL_CallFunc)(); typedef void (SelectorProtocol::*SEL_CallFuncN)(CCNode*); typedef void (SelectorProtocol::*SEL_CallFuncND)(CCNode*, void*); typedef void (SelectorProtocol::*SEL_CallFuncO)(CCObject*); typedef void (SelectorProtocol::*SEL_MenuHandler)(CCObject*); typedef void (SelectorProtocol::*SEL_EventHandler)(CCEvent*); #define schedule_selector(_SELECTOR) (SEL_SCHEDULE)(&_SELECTOR) #define callfunc_selector(_SELECTOR) (SEL_CallFunc)(&_SELECTOR) #define callfuncN_selector(_SELECTOR) (SEL_CallFuncN)(&_SELECTOR) #define callfuncND_selector(_SELECTOR) (SEL_CallFuncND)(&_SELECTOR) #define callfuncO_selector(_SELECTOR) (SEL_CallFuncO)(&_SELECTOR) #define menu_selector(_SELECTOR) (SEL_MenuHandler)(&_SELECTOR) #define event_selector(_SELECTOR) (SEL_EventHandler)(&_SELECTOR) }//namespace cocos2d #endif // __COCOA_SELECTOR_PROTOCOL_H__
위의 코드를 보면 셀렉터를 지정하는 매크로가 여러개임을 알 수 있습니다. 그것은 액션에 전해지는 인자의 타입 때문에 나뉘어 진 것 입니다. 그 종류를 나열해 보면 아래와 같습니다.
- schedule_selector
CCNode 의 schedule 메서드로 스케쥴을 걸 때 스케쥴 로직을 수행할 함수의 포인터를 정할 때 사용합니다.
- callfunc_selector
cocos2d에서 액션이 끝난 다음 함수를 호출할 때 호출할 함수의 포인터를 정할 때 사용합니다.
- callfuncN_selector
callfunc_selector 와 같지만 셀렉터를 호출한 CCNode의 포인터도 같이 전달해 줍니다.
- callfuncND_selector
callfunc_selector 와 같지만 셀렉터를 호출한 CCNode의 포인터와 추가적인 인자의 포인터도 같이 전달해 줍니다. 인자는 void *로 구조체, 문자열, 변수, 객체 등을 전달할 수 있습니다.
- callfuncO_selector
callfunc_selector 와 같지만 CCObject를 인자로 전달합니다.
- menu_selector
메뉴의 셀렉터입니다.
- event_selector
터치 이벤트와 관련있는 셀렉터입니다.
이제 위의 함수에 move 액션을 만들고 move액션이 끝난 다음에 적 스프라이트를 화면에서 지우는 CCCallFuncN 액션을 만들겠습니다. 아래와 같이 코드를 추가해 주세요.
//GameScene.cpp void GameScene::addTarget() { ... //: 속도를 랜덤으로 결정한다. int minDuration = (int)2.0; int maxDuration = (int)4.0; int rangeDuration = maxDuration - minDuration; int actualDuration = ( rand() % rangeDuration ) + minDuration; //: move액션을 만든다 CCFiniteTimeAction *actionMove = CCMoveTo::actionWithDuration((ccTime)actualDuration, ccp(0-target->getContentSize().width/2, actualY)); //: 적 스프라이트가 화면 밖에 나간 후에 호출될 콜백 액션 CCFiniteTimeAction *actionMoveDone =
CCCallFuncN::actionWithTarget(this,
callfuncN_selector(GameScene::spriteMoveFinished)); target->runAction(
CCSequence::actions(actionMove, actionMoveDone, NULL)); } void GameScene::spriteMoveFinished(CCNode *node) { this->removeChild(node, true); }
CCCallFuncN액션에서 액션에 설정한 셀렉터가 호출될 때 이 셀렉터를 호출한 CCNode가 같이 전달 되므로 화면을 벗어난 적 스프라이트가 전달 되는 것입니다. 따라서 해당 node포인터를 this(현재 GameScene)에서 removeChild() 를 해 주면 화면에서 지워지게 됩니다.
3. 게임 루프 메서드 설치하기
적이 주기적으로 계속 나오게 하기 위해서 게임 로직을 수행하는 gameLogic 메서드를 추가하겠습니다.
// GameScene.h //: 게임 로직을 수행합니다. //: addTarget()을 주기적으로 호출합니다. void gameLogic(cocos2d::ccTime dt);
아래와 같이 구현합니다.
// GameScene.cpp void GameScene::gameLogic(cocos2d::ccTime dt) { this->addTarget(); }
이제 이 GameLogic 메서드가 주기적으로 호출될 수 있도록 스케줄링을 걸어 줍니다. GameScene의 init() 메서드에 아래와 같이 추가해 줍니다.
// GameScene.cpp // 레이어를 초기화합니다. bool GameScene::init() { // CCLayerColor 의 initWithColor 초기자를 호출해 // 배경화면을 하얀색으로 변경한다. // 색상 설정은 ccc4(R, G, B, A) 매크로를 사용한다. if( !CCLayerColor::initWithColor(ccc4(255, 255, 255, 255)) ) { // 초기화에 실패하면 false를 반환합니다. return false; } //: 플레이어 스프라이트를 화면에 추가합니다. this->setPlayerSprite(); //: 게임 로직을 만든다 this->schedule(schedule_selector(GameScene::gameLogic), 1.0); return true; }
이제 코드의 작성이 모두 끝났습니다. 편의를 위해서 GameScene의 모든 코드를 올립니다.
// // GameScene.h // NinjaGame // // Created by SUNG CHEOL KIM on 11. 10. 12.. // Copyright 2011 individual. All rights reserved. // #ifndef NinjaGame_GameScene_h #define NinjaGame_GameScene_h #include "cocos2d.h" //: 배경화면 색상 변경을 위해서 CCLayerColor를 상속받는다 class GameScene : public cocos2d::CCLayerColor { public: //: 초기자 //: 아이폰용 cocos2d에서는 id를 반환하지만 cocos2d-x에서는 bool을 반환해야 합니다. virtual bool init(); //: CCScene을 반환하는 클래스 메서드 //: 아이폰에서 cocos2d로 게임을 만들 때 CCLayer를 상속받은 커스텀레이어에서 //: 이런 식으로 클래스 메서드를 만들어서 씬을 많이 반환해 보셨을 겁니다. static cocos2d::CCScene* scene(); //: static node() 메서드를 구현합니다. LAYER_NODE_FUNC(GameScene); private: //: 플레이어의 스프라이트를 추가합니다. void setPlayerSprite(); //: 적 스프라이트를 랜덤 위치와 속도로 화면에 추가합니다. void addTarget(); //: 적 스프라이트가 화면에서 사라진 후 스프라이트를 씬과 메모리에서 제거합니다. void spriteMoveFinished(CCNode *node); //: 게임 로직을 수행합니다. //: addTarget()을 주기적으로 호출합니다. void gameLogic(cocos2d::ccTime dt); }; #endif
// // GameScene.cpp // NinjaGame // // Created by SUNG CHEOL KIM on 11. 10. 12.. // Copyright 2011 individual. All rights reserved. // #include "GameScene.h" //using namespace cocos2d 의 약자 매크로입니다. USING_NS_CC; CCScene* GameScene::scene() { // GameScene레이어를 담아 반환할 씬을 하나 만듭니다. // 자동 메모리 해제 되는 인스턴스입니다. CCScene *scene = CCScene::node(); // 레이어를 생성합니다. GameScene *layer = GameScene::node(); // 레이어를 자식으로 씬에 추가합니다. scene->addChild(layer); return scene; } // 레이어를 초기화합니다. bool GameScene::init() { // CCLayerColor 의 initWithColor 초기자를 호출해 // 배경화면을 하얀색으로 변경한다. // 색상 설정은 ccc4(R, G, B, A) 매크로를 사용한다. if( !CCLayerColor::initWithColor(ccc4(255, 255, 255, 255)) ) { // 초기화에 실패하면 false를 반환합니다. return false; } //: 플레이어 스프라이트를 화면에 추가합니다. this->setPlayerSprite(); //: 게임 로직을 만든다 this->schedule(schedule_selector(GameScene::gameLogic), 1.0); return true; } void GameScene::setPlayerSprite() { //: 화면 좌측, 중간에 놓기 위해서 화면 크기를 이용합니다. CCSize winSize = CCDirector::sharedDirector()->getWinSize(); //: 플레이어 이미지를 불러와 스프라이트를 만듭니다. //: CCRectMake는 스프라이트의 영역을 만듭니다. //: 이미지 크기와 동일하게 만들어 줍니다. CCSprite *player = CCSprite::spriteWithFile("Player.png", CCRectMake(0, 0, 27, 40)); //: 플레이어의 위치를 정해줍니다. player->setPosition( ccp(player->getContentSize().width/2, winSize.height/2) ); //: GameScene에 스프라이트를 추가합니다. this->addChild(player); } void GameScene::addTarget() { //: 적 스프라이트를 만든다. CCSprite *target = CCSprite::spriteWithFile("Target.png", CCRectMake(0, 0, 27, 40)); //: 적 스프라이트의 Y 좌표를 랜덤으로 하여 위치를 잡는다 CCSize winSize = CCDirector::sharedDirector()->getWinSize(); int minY = target->getContentSize().height/2; int maxY = winSize.height - target->getContentSize().height/2; int rangeY = maxY - minY; int actualY = ( rand() % rangeY ) + minY; target->setPosition( ccp(winSize.width + (target->getContentSize().width/2), actualY) ); this->addChild(target); //: 속도를 랜덤으로 결정한다. int minDuration = (int)2.0; int maxDuration = (int)4.0; int rangeDuration = maxDuration - minDuration; int actualDuration = ( rand() % rangeDuration ) + minDuration; //: move액션을 만든다 CCFiniteTimeAction *actionMove = CCMoveTo::actionWithDuration((ccTime)actualDuration, ccp(0-target->getContentSize().width/2, actualY)); //: 적 스프라이트가 화면 밖에 나간 후에 호출될 콜백 액션 CCFiniteTimeAction *actionMoveDone =
CCCallFuncN::actionWithTarget(this,
callfuncN_selector(GameScene::spriteMoveFinished)); target->runAction(CCSequence::actions(actionMove, actionMoveDone, NULL)); } void GameScene::spriteMoveFinished(CCNode *node) { this->removeChild(node, true); } void GameScene::gameLogic(cocos2d::ccTime dt) { this->addTarget(); }
아래 화면은 결과화면입니다.
이번 튜토리얼은 여기서 마치고 다음 튜토리얼에서는 총알을 화면에 추가해 보겠습니다 :)
'게임개발팁' 카테고리의 다른 글
cocos2d-X 게임 만들기 5편 (7) | 2011.11.18 |
---|---|
cocos2d-X 게임 만들기 4편 (4) | 2011.11.09 |
cocos2d-X 게임 만들기 2편 (8) | 2011.10.13 |
cocos2d-X 게임 만들기 1편 (14) | 2011.10.12 |
iOS OpenGL | ES 튜토리얼 3편 (3) | 2011.10.02 |