티스토리 뷰

프로그래밍/게임 개발

[Cocos2D-X] Advanced Animation Class

터프 프로그래머 2012. 1. 26. 13:49

AdvancedSpriteAnimation.cpp

AdvancedSpriteAnimation.h


그냥 소스만 주는 것은 좋지 않은 것이라는 걸 저도 알고, 다른 분들도 알고 있다고 생각합니다.
하지만 뭔가를 이해하는데 가장 좋은 방법도 소스를 보는 방법입니다.
그래서 일단 소스를 첨부하고 시작하도록 하겠습니다.

제가 만든 애니메이션 클래스는 한 파일 안에 여러 애니메이션 이미지가 들어 있는 이미지를 이용하는 클래스인데요.
일단 간단하게 구현하기 위해 세로로 여러 줄을 지원하진 않고, 가로로 한 줄만 지원하도록 하였습니다.
(만드는 게임에 많은 애니메이션을 요구하는 것이 아니라 이렇게 만든 부분도 있습니다.
 보통 만들 때에는 프레임 당 가로, 세로 길이를 넣어서 java에서 문자열을 split 하듯이 그림을 2차원 배열로 만들어서 각각의 인덱스에 해당하는
 프레임을 뽑아오더군요.)

1. 팩토리 패턴
만든 클래스를 cocos2d 클래스들 처럼 팩토리 패턴으로 인스턴스를 넘겨주도록 합니다.
###cpp
static CAdvancedSpriteAnimation* aniWithFile(const char *pszFileName,
float frameRate, int totalIndex,
float frameWidth, float frameHeight,
int startIndex, int endIndex, bool looping = false);
 
pszFileName - 그림 파일 위치
frameRate - 한 프레임당 걸리는 시간
totalIndex - 총 프레임 갯수
frameWidth - 한 프레임 가로 크기
frameHeight - 한 프레임 세로 크기
startIndex - 처음 프레임(1부터 시작)
endIndex - 마지막 프레임

startIndex와 endIndex가 왜 있냐 하면 무조건 처음부터 끝까지의 애니메이션을 돌리고 싶지 않은 경우도 있기 때문에 넣었습니다.
이 팩토리 패턴 함수를 이용하여 객체를 생성할 때 만든 객체를 클래스 함수 중 있는 init()와 autorelease()를 걸어주고 반환합니다.

2. 클래스 초기화 함수( init() )
### cpp
void CAdvancedSpriteAnimation::init(const char *pszFileName, float frameRate, int totalIndex,float frameWidth, float frameHeight,int startIndex, int endIndex, bool looping)
{
        CCSprite::init();

        this->frameRate = frameRate;
        this->totalIndex = totalIndex;
        this->frameWidth = frameWidth;
        this->frameHeight = frameHeight;
        this->startIndex = startIndex;
        this->endIndex = endIndex;
        this->looping = looping;

        CC_SAFE_DELETE_ARRAY(frameList);
        frameList = new CCMutableArray<CCSpriteFrame*>;

        //Texture load with Cache
        CCTexture2D *texture = CCTextureCache::sharedTextureCache()->addImage(pszFileName);

        //frame add
        for( int i = 0; i < totalIndex; i++ )
        {
                 CCSpriteFrame *frame = CCSpriteFrame::frameWithTexture(texture,
                 CCRectMake(frameWidth*i, frameHeight*0, frameWidth, frameHeight) );
                 frameList->addObject(frame);
        }
        currIndex = startIndex;
        setDisplayFrame( frameList->getObjectAtIndex(currIndex) );
}
init 함수에서는 전체적으로 애니메이션을 하기 위해서 프레임들을 추가해주고 클래스를 정리하는 역할을 합니다.
이 클래스는 CCSprite를 상속받은 클래스인데 아까 말씀 드렸던 autorelease()를 걸어주기 위해 CCSprite::init()을 먼저 해줍니다.
(여기서 레퍼런스카운터를 사용하기 위한 준비를 해줍니다.
그리고 인자로 받아온 변수들을 클래스에 저장시키고 프레임 리스트에 프레임들을 추가합니다.
마지막으로 setDisplayFrame() 함수로 처음으로 보여질 프레임을 적용하면 끝입니다.

3. addFrame()
혹시 더 추가할 프레임이 생길 땐 이 addFrame() 함수를 이용하여 프레임을 추가합니다.
그냥 CCSpriteFrame* 으로 한 장씩 추가할 수도 있고, CCMutableArray<CCSpriteFrame*>*으로 여러 프레임이 들어있는 mutable array를 추가할 수도 있습니다.

4. update(ccTime dt)
### cpp

void CAdvancedSpriteAnimation::update(ccTime dt)
{
         if( !playing )
                 return;

         elapsedTime += dt;
         while( elapsedTime >= frameRate )
         {
                 elapsedTime -= frameRate;
                 currIndex ++;
                 if(currIndex > endIndex && looping == true)
                         currIndex = startIndex;
         }
         setDisplayFrame( frameList->getObjectAtIndex(currIndex) );
애니메이션 클래스에서 매우 중요한 업데이트 함수 입니다.
현재 프레임에서 쌓인 시간을 구하여 한 프레임 당 대기해야 할 시간을 초과하였으면 다음 프레임으로 바꿔주는 역할을 합니다.
이 update 함수는 layer해서 매 프레임당 호출하여 시간을 쌓아줘야 합니다.
while으로 현재 쌓인 시간이 한 프레임 당 대기해야 할 시간 * 2 이상일 경우을 처리해줄 수 있습니다.
마지막으로 바뀐 index에 해당하는 프레임을 불러와서 setDisplayFrame()을 해주면 끝입니다!

5. Order
반복해서 재생을 할 것인지, 그리고 재생을 할 것인지 명령을 해줘야 합니다.
필요한 때에 재생을 시키고 필요 없을 때 재생을 하지 않을 필요가 있으니까요.
### cpp
void playOrder(bool playing) {this->playing = playing;}
void loopOrder(bool looping) {this->looping = looping;} 
bool형 인자로 오더를 내립니다.



제가 쓰기 위해 만든 클래스이다 보니 제 상황에 많이 적합한 클래스입니다. 글에는 쓰지 않았지만 소스 내부에는 메소드가 좀 더 있습니다.
제가 만든 툴이 있는데 그 툴 exe 파일이 존재하는 곳에 있는 모든 그림파일을 불러와서 한 줄로 정리하여 스프라이트 이미지로 만들어 주는 툴이 있는데요. 이렇게 한 줄로 정리해 주는 툴을 만들어 쓰다보니 여러 줄로 만들어져 있는 스프라이트 이미지를 처리하는 클래스를 만들어야 할 이유가 없었습니다. 물론 여러 줄의 스프라이트 이미지도 처리할 수 있도록 클래스를 개량하는 일은 어려운 일은 아닙니다만 제가 하질 않고 있네요 :)

그럼 오늘도 즐거운 하루 되세요. 
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday