본문 바로가기

cocos2d-x/pyocopang

cocos2d-x 포코팡 류 게임만들기!! - 14 - 시간 제한

드디어! 제가 계획한 내용의 마지막입니다. 초기화면에서 게임화면으로 전환되는 부분까지 지난 시간에 만들어봤고요. 이번에는 시간제한 부분을 추가해서 정해진 시간이 완료되면 게임을 중단하고 다시 초기화면으로 돌아가도록 해보겠습니다.


- 14 - 시간 제한


1. 화면 구성


기대하는 화면 구성은 다음과 같은데요. 처음 어플을 실행하면, '초기화면'이 나오고, 터치를 하면, '게임화면', 여기서 '60초'가 지나면, 다시 '초기화면', 터치를 하면, '게임화면'...'초기화면','게임화면',... 계속 반복입니다.

게임화면 하단에 노란색 타임바를 추가하여 60초 동안 오른쪽에서 왼쪽으로 줄어들도록 합니다. 다 줄어들면 다음 화면인 초기화면으로 넘어가게 됩니다. 그럼 구현을 해보도록 하겠습니다.


2. CCProgressTimer


게임 하단의 타임바는 꽉 찬 상태에서 60초 동안 왼쪽으로 서서히 줄게될 것입니다. CCProgressTimer라는 class를 통해서 만들게 될텐데요. 이 클래스는 게임에서 게이지가 늘어나거나 줄어들거나 하는 형태를 표현할 수 있게 도움을 줍니다. 바(bar)형태의 게이지를 나타낼 수도 있고, 원형의 중심점을 기준으로 줄어들거나 늘어나는 형태도 표현할 수 있습니다.

이미지는 다음의 두 이미지를 사용합니다. 


timebar.png


timeoutline.png

위에는 실제 시간이 줄어드는 것을 표현하기 위한 용도로 쓰이고, 아래의 이미지는 단순히 외곽선을 표현하는데 사용합니다.


/Classes/HelloWorldScene.h

class HelloWorld : public cocos2d::CCLayer
{
private:
    ...
    CCProgressTimer* _progressTimeBar;
    ...
};

/Classes/HelloWorldScene.cpp

void HelloWorld::createGameScene()
{
    ...
    CCSprite* timeBar = CCSprite::create("timebar.png");
    _progressTimeBar = CCProgressTimer::create(timeBar);
    _progressTimeBar->setPosition(ccp(_screenSize.width * 0.5f, 27));
    _progressTimeBar->setPercentage(100.0f);
    _progressTimeBar->setMidpoint(ccp(0, 0.5f));
    _progressTimeBar->setBarChangeRate(ccp(1, 0));
    _progressTimeBar->setType(kCCProgressTimerTypeBar);

    this->addChild(_progressTimeBar);

    CCProgressFromTo* progressToZero = CCProgressFromTo::create(60, 100, 0);
    _progressTimeBar->runAction(progressToZero);

    CCSprite* timeOutline = CCSprite::create("timeoutline.png");
    timeOutline->setPosition(ccp(_screenSize.width * 0.5f, 27));
    timeOutline->setVisible(true);
    this->addChild(timeOutline);

    initGameCoin();
}

아래의 timeoutline.png 관련한 부분은 단순히 이미지를 추가한 내용이라 생략하도록 하고요. timebar.png에 대해 살펴보도록하겠습니다. 기본적으로 다른 class와 사용방법은 같습니다. 이미지를 추가하고, 위치 및 다른 정보를 설정하고 액션이 필요하면 액션을 추가합니다. 

제일 아래부터 setType()을 통해 바 또는 원형을 선택합니다. 저희는 바형태를 사용하기 때문에 kCCProgressTimerTypeBar라는 enum값을 사용합니다. 바형태는 세로 또는 가로로 사용할 수 있는데요. 오른쪽에서 왼쪽으로 줄어드는 동작을 하기로 했기 때문에, 위와 같은 값을 사용했습니다. 세로로 하는 방법이나 방향을 바꾸고 싶으면 값을 한 번 바꿔보세요. 자세한 내용은 항상 reference 문서를 보도록 합니다. 사실 제 설명이 필요없을 만큼 잘 정리되어 있습니다.

CCProgressTimer class <- Click!!

방향 설정은 잘 해줬고요. 이제는 액션을 추가해서 원하는대로 동작하도록 해보겠습니다. 

CCProgressFromTo 라는 class로 액션을 추가하는데요. create(60, 100, 0)에서 대충알 수 있는 것 처럼, 60초 동안 100에서 0으로 동작하는 액션입니다. 

액션까지 추가하고 돌려보면!! 잘 돌아가는군요. 하지만 60초가 지나도 뭐 아무것도 없습니다. 물론 60초 이후에 따로 뭘 시키지 않아서 그런거겠죠. 이전에 액션들을 chain형태로 연결해서 동작도 시켜보고, 액션 마지막에 처리할 수 있는 동작을 추가하는 것도 해봤으니 이번에는 다른 방법을 사용해보도록 하겠습니다. 

_gameTime이란 변수를 '60'으로 초기화하고, 1초마다 1씩 줄여가면서 0이 되면 다시 초기화면으로 돌아가도록 합니다. 보통은 timer를 통해 원하는 시간이 지나면 필요한 동작처리하는데, cocos2d-x에서는 schedule 함수를 통해서 처리하는 모양입니다. 

/Classes/HelloWorldScene.h

class HelloWorld : public cocos2d::CCLayer
{
private:
    ...
    CCProgressTimer* _progressTimeBar;
    int _gameTime;
    
public:
    ...
    void timeCount();
    void changeToOpeningScene();
};

_gameTime 변수에 시간값을 저장합니다. timeCount()에서 매 초 시간을 체크해서 '0'이 되면, changeToOpeningScene() 함수를 호출합니다. 

/Classes/HelloWorldScene.cpp

void HelloWorld::initGameCoin()
{
    ...
    _gameTime = 60;  // 60 sec.
}

initGameCoin()에서 제한시간을 60초로 초기화하고요.

/Classes/HelloWorldScene.cpp

void HelloWorld::timeCount()
{
    if (--_gameTime == 0) {
        changeToOpeningScene();
    }
}

void HelloWorld::changeToOpeningScene()
{
    this->unschedule(schedule_selector(HelloWorld::timeCount));
    CCScene* pScene = Opening::scene();

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

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

timeCount()에서 _gameTime 값을 줄이면서 0이 되었는지 확인합니다. 0이 되면 changeToOpeningScene()을 호출합니다. changeToOpeningScene() 내용은 이전 화면전환에서 보았던 내용 그대로입니다. 1초 동안 초기화면으로 서서히 전환하게 되겠습니다. 조금 다른 부분이 첫 줄에 보이는데요. unschedule()함수는 조금 있다 나올 schedule()의 반대되는 개념으로 주기적으로 동작하는 함수의 동작을 정지하는 역할을 합니다. 화면 전환 후에는 시간제한을 계산해줄 필요가 없기 때문에, 필요없는 동작은 하지 않도록 해줍니다.

OpeningScene으로 전환하려면, Opening class가 포함된 헤더파일을 포함시키는 것을 잊지말아야겠죠.

/Classes/HelloWorldScene.h

#ifndef __HELLOWORLD_SCENE_H__
#define __HELLOWORLD_SCENE_H__

#include "cocos2d.h"
#include "GameCoin.h"
#include "OpeningScene.h"

using namespace cocos2d;

class HelloWorld : public cocos2d::CCLayer
{
private:

헤더파일을 잘 추가해주고 나서, timeCount()가 주기적으로 호출되도록 schedule 합니다.

/Classes/HelloWorldScene.cpp

bool HelloWorld::init()
{
    //////////////////////////////
    // 1. super init first
    if ( !CCLayer::init() )
    {
        return false;
    }

    createGameAction();
    createGameScene();

    this->schedule(schedule_selector(HelloWorld::timeCount), 1.0f);

    this->setTouchEnabled(true);

    return true;
}

schedule()에 timeCount()함수를 지정하고, 시간은 1.0f로 설정하여 1초마다 timeCount가 호출되도록 합니다. 그러면 schedule함수가 동작한 순간부터 1초마다 timeCount()가 호출되면서 _gameTime값이 줄어들고 결국 60초 뒤에 화면을 전환하게 됩니다.

그런데 schedule()함수로 그냥 60초를 설정해도 될 것 같은데, 왜 이렇게 했을까요...--; 1초도 정확하게 측정할 정밀도면 60초도 잘 계산해줄 것 같은데 말이죠.

자! 이제 마지막 코드까지 추가되었으니 빌드해서 동작해보겠습니다! 어떻게 잘 동작하시나요?



시간 제한까지 마쳤습니다. 뭔가 다 작성하고 나니 아쉽네요. 방문자 분들은 적지만 꾸준히 봐주시는 분들이 계셔서 기분좋았고요. 부족한 글 끝까지 읽어주셔서 너무 감사했습니다.

진짜로!!!! 끝!!! 와아~!