이번 강좌는 Ease Actions와 Misc Actions 라는 Action들을 배울 것이다. 그런데 생각보다 어렵다. 잘 이해가 되지 않는 것은 예제도 실행해보면서 다시한번 살펴봐라. 그리고 그래도 이해가 되지 않는다면 댓글을 달아주시길...


그럼 강좌를 시작하겠다. 


Cocos2d로 애니메이션 구현하기 3


3. Ease Actions


Ease Action은 애니메이션을 구현하는 속도에 관련된 Action들이다. 이제까지 알아본 것은 모두 기본 속도 1로 작동하는 것들인데 Ease Action을 통해서 애니메이션을 점점빠르게 갑자기 빠르게 등을 구현해 볼 수 있다. 

3.1 EaseIn / EaseOut


EaseIn은 이동이나 변환등의 액션을 처음에는 천천히 시작했다가 점점 빨라지는 애니메이션을 구현한다. 그러니까. 점점 빨라지는 Action 이다. Move Action을 사용하면 쉽게 이해할 수 있는데 특정 지점으로 이동하는 Action을 EaseIn에 등록하고 실행시키면 해당 지점으로 빨려들어가듯이 점점 빨리 움직이는 것을 볼 수 있다. EaseOut은 EaseIn과 반대로 처음에는 빨리 시작되었다가 점점 느려지는 애니매이션을 구현한다. Move Action에서 다시 생각해 보자면 특정 위치에서 빨리 빠져나와서 점점 지정된 위치로 이동하는 것으로 이해하면 쉽게 이해할 수 있을 것이다. 

다음 그림을 보면서 이해를 하도록 노력해 보자. x축은 시간이고 y축은 전체를 1로 봤을 때 처리한 프레임 수의 비율이다. 만약 Move라면 이동한 거리라 볼 수 있고, Rotate라면 회전한 각도 비율이라 볼 수 있다.

EaseInOut.png 

파란색은 EaseIn을 빨간색은 EaseOut의 Rate계산식을 나타낸 것이다. 그리고 가운데 검은 선은 기본 애니메이션 구현속도이고, 양 옆의 희미한 색의 그래프는 rate값을 좀더 크게했을 때의 속도그래프이다. 이 그래프를 보면 알 수 있듯이 EaseIn은 처음에는 느린 속도로 애니메이션하다가 점점 빠르게 애니메이션을 구현한다. EaseOut은 이와 반대로 처음에는 매우 빠른 속도로 애니메이션을 구현하다가 점점 느린 속도로 구현되도록 계산하는 것을 확인할 수 있다. 
 

사 용방법은 다음과 같이 Action을 하나 만들고 그 Action을 [EaseIn actionWithAction:rate:]에 입력되는 Action을  rate만큼의 로그 비율로 점점 빨라진다. rate의 값이 크면 클 수록 처음에는 더 느리고 중간 이동하는 속도가 더 빨라진다.

    id move = [MoveBy actionWithDuration:3 position:ccp(350,0)];
    id move_ease_in = [EaseIn actionWithAction:[[move copy] autorelease] rate:3.0f];
    [someSprite runAction:move_ease_in];

EaseOut도 동일한 방법으로 구현할 수 있다. 단, rate값이 크면 클 수 록 처음에 실행되는 애니메이션의 속도가 빨라지고 중간에 이동하는 속도는 급격히 떨어진다.


다음은 EaseIn/EaseOut이 실행되는 화면이다.

맨 위는 EaseIn을 두번째는 EaseOut을 세번째는 비교를 위해 기본 속도의 애니메이션을 출력한 것이다. 

(용량상 캡춰를 짧게 해서 잘 모를지도 모른다. 그럴 경우에는 밑에 소스를 첨부했으니 실행해 보자.)


3.2 EaseInOut


EaseInOut은 EaseIn과 EaseOut을 연속해서 실행하는 것과 동일한 결과를 얻을 수 있다. 처음에는 느리게 실행되었다가 점점 속도가 빨라졌다가 다시 점점 느려지는 애니메이션이 구현된다. 


다음은 실행되는 화면이다.

처음은 비율을 3.0f로 했을 경우이고 두번째는 5.0f로 했을 경우이다. 어떻게 차이가 있는지 비교해 볼 수 있다. 


3.3 EaseSineIn / EaseSineOut


EaseSineIn과 EaseSineOut은 EaseIn과 EaseOut의 rate를 Sine값으로 대체한 것이다. 그래서 Sine그래프처럼 처음에는 느리게 실행되다고 점점 빨라지다가 다시 느려지고, 말로 설명을 하려니까. 좀 힘이 든다. ㅜㅜ. 

다음의 이미지는 실제로 SineIn과 SineOut을 할 때 식의 그래프이다.

EaseSine.png 

빨간색이 SineIn의 애니메이션의 속도 변화값이고, 파란색이 SineOut의 애니메이션의 속도 변화값이다. 그리고 검은색은 Rate가 1일 때 일반적인 속도를 나타낸 것이다. 
이 그림을 보면 대충 짐작하겠지만 SineIn은 기본 애니메이션보다 느리게 출발하지만 점점 빨라지고, SineOut은 처음에는 빨리 출발하지만 점점 느려진다.

다음에 실행되는 화면을 추가할 테니 보시면서 잘 이해하길 바란다. ^^;;;


구현하는 방법은 다음과 같이 단순히 속도 조절을 원하는 Action을 입력받는다.

    id move = [MoveBy actionWithDuration:3 position:ccp(350,0)];
    id move_ease_in = [EaseSineIn actionWithAction:[[move copy] autorelease]];
    [someSprite runAction:move_ease_in];


다음은 실행되는 화면이다.

위의 것이 EaseSineIn이고 중간의 것이 EaseSineOut이고 마지막의 것이 기본 속도로 움직이는 것이다. 


3.4 EaseSineInOut


EaseSineInOut은 EaseSineIn과 EaseSineOut을 합쳐놓은 것과 같은 속도로 애니메이션을 구현하고 이를 계산하는 식의 그래프는 다음과 같다. 

EaseSineInOut.png 

구현하는 방법은 EaseSineIn이나 EaseSineOut과 동일하다.


다음은 실행되는 화면이다. 

 


3.5 EaseExponential


EaseExponential은 영어를 해석하자면 지수적인이란 접미어가 붙었는데 말그대로 지수로 애니메이션의 속도가 변한다. 그러므로 급격히 빨라지거나 급격히 느려지는 것을 구현할 때 사용하면 된다. 
다음은 EaseExponentialIn과 EaseExponentialOut의 속도 계산식을 그래프로 그린 것이다. 


EaseExponetial.png

빨간색이 EaseExponentialOut을 파란색이 EaseExponentialIn의 속도 변화를 그린 것이다. 그래프를 봐서 쉽게 이해되지 않는다면 다음 애니메이션을 참고해보자.

구현하는 방법은 EaseSine과 동일하게 속도를 변화하려는 Action만을 다음과 같이 입력하면 된다. 

    id move = [MoveBy actionWithDuration:3 position:ccp(350,0)];
    id move_ease_in = [EaseExponentialIn actionWithAction:[[move copy] autorelease]];
    [someSprite runAction:move_ease_in];


다음은 실행하는 화면이다.

 맨위가 EaseExponentialIn이고 두번째가 EaseExponentialOut이고 세번째에 비교를 위해서 기본 속도의 애니를 추가했다.



3.6 EaseExponentialInOut


EaseExponentialInOut 은 EaseExponentialIn과 EaseExponentialOut을 연속해서 실행시킨 것과 동일한 기능을 한다. 먼저 처음에는 느리게 시작되다가 갑자기 빨라지다가 목적지에 거의 도달해서 갑자기 느려진다. 초기위치에 도달위치를 알려주고 순간이동과 같은 경우를 구현하고자 할 때 사용하면 좋을 것 같다. 

실행하는 방법은 EaseExponentialIn이나 EaseExponentialOut과 같다. 

3.7 Speed


Speed는 Action의 속도를 중간 중간에 변경할 때 유용하게 사용할 수 있다. 초기에 생성시에 [Speed actionWithAction:speed:]로 해당 Action을 speed파라미터로 입력된 속도로 일정하게 애니메이션을 동작시키다가 [speedAction setSpeed:]로 해당 애니메이션 동작 속도를 변경할 수 있다. API에 보면 슬로모션이나 빠른 건너뛰기를 할 때 유용하게 사용할 수 있다고 합니다. 

다음은 점프하면서 회전하는 이미지를 1초마다 Scheduler를 통해서 속도를 변경시키는 예제이다. 매 초마다 변경할 속도는 랜덤한 값으로 설정하도록 설정한 예제이다.

- (void)onEnter
{
    [super onEnter];

    // rotate and jump
    IntervalAction *jump1 = [JumpBy actionWithDuration:4 position:ccp(-400,0) height:100 jumps:4];
    IntervalAction *jump2 = [jump1 reverse];
    IntervalAction *rot1 = [RotateBy actionWithDuration:4 angle:360*2];
    IntervalAction *rot2 = [rot1 reverse];

    id seq3_1 = [Sequence actions:jump2, jump1, nil];
    id seq3_2 = [Sequence actions: rot1, rot2, nil];
    id spawn = [Spawn actions:seq3_1, seq3_2, nil];
    id action = [Speed actionWithAction: [RepeatForever actionWithAction:spawn] speed:1.0f];
    [action setTag: kTagAction1];

    [someSprite runAction:action];

    [self schedule:@selector(altertime:) interval:1.0f];    // schedule을 등록한다.
}

- (void)altertime:(ccTime)dt
{
    id action = [someSprite getActionByTag:kTagAction1];

    [action setSpeed: CCRANDOM_0_1() * 2];
}

4. Mics Actions


4.1 CallFunc


CallFunc는 callback 메소드를 호출해서 실행시킨다. Sequence로 애니메이션을 다 구현한 후에 메소드를 실행시키려도 할 때 유용하게 사용할 수 있다. 
CallFunc는 [CallFunc actionWithTarget:selector:]를 사용해서 callback메소드를 입력하는 Action을 만들 수 있다. 

다음은 가로로 200이동한 후에 Callback을 호출하는 예제이다. 

-(void) onEnter
{
    [super onEnter];
    
    id action = [Sequence actions:
                 [MoveBy actionWithDuration:2 position:ccp(200,0)],
                 [CallFunc actionWithTarget:self selector:@selector(callback)],
                nil];
    [someSprite runAction:action];
}

-(void) callback
{
    [tamara setVisible:YES];
}

4.2 Orbit(궤도)


Orbit는 화면의 가운데를 중심으로 하는 구형의 좌표계에서 해당 Sprite를 궤도를 따라 움직이게 하는 Action이다. Orbit의 구현은 다음의 메소드를 사용한다. 
    [OrbitCamera actionWithDuration:        // 애니메이션 구현 시간
                        radius:deltaRadius:        // 시작지 및 목적지의 거리(반경) - 원근을 표시할 때 사용하면 좋음
                        angleZ:deltaAngleZ:        // Z축의 시작지 및 목적지 각도
                        angleX:deltaAngleX:        // X축의 시작지 및 목적지 각도

Orbit 구현은 구형 좌표계가 익숙하지 않으니까 이해하기가 쉽지가 않다. 다음의 예제를 가지고 값을 바꿔가면서 실행해보면 어느 정도는 이해가 될 것이다. 

    id orbit = [OrbitCamera actionWithDuration: 2 radius:0.5f deltaRadius:1 angleZ:0 deltaAngleZ:180 angleX:0 deltaAngleX:0];
    id action = [Sequence actions:orbit, [orbit reverse], nil];
    [someSprite runAction:action];



이제 Cocos2d로 구현할 수 있는 대부분 애니메이션의 Action을 알아봤다. 어떤 것이든 지금까지 배운 것을 다 조합하면 다 구현할 수 있을 것이다. 마지막으로 3번째 애니메이션 구현의 예제를 추가하겠다. SpriteTest3.zip 이것은 Cocos2d Test의 sample예제를 강좌를 위해서 편집한 것이다. 그럼 열심히 공부하시길... 


다음에는 터치이벤트를 받아서 처리하는 법을 배우겠다. 머 다들 알겠지만 간단히 훌른다는 기분으로 준비하려고 한다. 

그럼 다음 강좌를 기대하시라... ^^