폭발 효과 에니매이션 

총알에 맞은 적 또는 플레이어 케릭터가 적과 충돌할 경우에 폭발하는 애니메이션이 보이게 된다. cocos2d에서 제공하는 파티클을 사용하여서 폭발하는 효과를 더 현실감 있고 화려하게 구현 하는 방법도 있다. 이 튜토리얼에서는 한두가지의 이미지로 폭발 파티클 효과를 비슷하게 구현하도록 하겠다. 


폭발 스프라이트 애니메이션을구현 하기 위해서 CCSprite를 상속 받아서 Dust 라는 이름으로  클래스를 만든다. 


Dust.h 로 이동하여 아래 코드를 추가한다. 

@interface Dust : CCSprite {

  CCArray *dusts;

  CCArray *explosions;

}


@property (nonatomic, weak) CCSpriteBatchNode *batch;


-(void)animateDusts;

-(void)animateExplosions;

폭발할 때 일어나는 먼지 스프라이트를 저장하는 배열과 폭발효과의 스프라이트를 저장하는 배열을 생성한다. 그리고 효과적으로 스프라이트를 사용하기 위한 배치노드를 프로퍼티를 만든다. 먼지효과 애니메이션과 폭발 애니메이션을 실행하는 메소드 2개를 생성한다. 


구현을 위해 Dust.m 으로 이동한다. 

폭발을 위한 초기 설정을 위해 init 메소드에 아래 코드를 추가한다. 

- (id)init

{

  self = [super init];

  if (self) {

    self.anchorPoint = CGPointZero;

    //동일한 이미지의 반복 사용의 효율성을 위해서 배치노드 생성

    _batch = [CCSpriteBatchNode batchNodeWithFile:@"dragonRideSprite.pvr.ccz"];

    //배치노드 추가

    [self addChild:_batch];

    

    //10개의 먼지 이미지를 사용할 배열을 만든다.

    dusts = [CCArray arrayWithCapacity:kMaxDust];

    for ( int i = 0 ; i < kMaxDust; i++ ) {

      //먼지 이미지를 스프라이트 시트에서 가져온다.

      CCSprite *dust = [CCSprite spriteWithSpriteFrameName:@"dust.png"];

      //에니메이션 될때 보여 주기 위해 처음에는 숨긴다.

      dust.visible = NO;

      //작은거에서 커지는 에니메이션을 위해 1/10 으로 작게 만든다.

      dust.scale = 1.0/10.0;

      //배치 노드에 자식 노드로 추가 한다.

      [_batch addChild:dust];

      //배열에 먼지를 추가한다.

      [dusts addObject:dust];

    }

    

    //플레이어 캐릭터가 폭발될 때의 스프라이트를 위한 배열

    explosions = [CCArray arrayWithCapacity:kMaxDust];

    

    //오른쪽  폭발 효과 스프라이트

    CCSprite *rightDamage = [CCSprite spriteWithSpriteFrameName:@"damage.png"];

    //폭발시에만 보이게, 숨김 처리

    rightDamage.visible = NO;

    //터지는 효과를 위해 작게 설정한다.

    rightDamage.scale = 0.5;

    rightDamage.anchorPoint = ccp( 0.0, 0.0 );

    [self addChild:rightDamage];

    [explosions addObject:rightDamage];


    //왼쪽 폭발 효과 스프라이트

    CCSprite *leftDamage = [CCSprite spriteWithSpriteFrameName:@"damage.png"];

    //폭발시에만 보이게, 숨김 처리

    leftDamage.visible = NO;

    //터지는 효과를 위해 작게 설정한다.

    leftDamage.scale = 0.5;

    // 동일한 이미지를 왼쪽에 사용하기 위해서 X, Y 뒤집기(플립)처리

    leftDamage.flipX = YES;

    leftDamage.flipY = YES;

    leftDamage.anchorPoint = ccp( 1.0, 1.0 );

    [self addChild:leftDamage];

    [explosions addObject:leftDamage];

    

    // 가운데 처지는 스프라이트

    CCSprite *explosion = [CCSprite spriteWithSpriteFrameName:@"explosion_01.png"];

    //폭발시에만 보이게, 숨김 처리

    explosion.visible = NO;

    //터지는 효과를 위해 작게 설정한다.

    explosion.scale = 0.5;

    [self addChild:explosion];

    [explosions addObject:explosion];

  }

  return self;

}

코드는 길지만 원리는 간단하다. 우선 먼지 애니메이션의 경우에는 하나의 이미지를 효과적으로 사용하기 위해서 배치노드를 생성한다. 그리고 먼지 이미지 10개를 숨김으로 해서 1/10 크기로 배치노드에 추가 한다. 폭발 애니메이션의 경우에도 이미지를 숨김으로 해서 1/2 크기로 추가 한다. 왼쪽 이미지의 경우에만 뒤집기 효과인 플립을 줘서 X, Y축으로 뒤집는다.  그리고 터지는 스프라이트도 동일하게 추가 한다. 


초기화는 되었으니 플레이어와 적이 충돌하였을 경우에 일어나는 애니메이션을 구현하도록 하겠다. animateExplosions 메소드에 아래코드를 추가한다. 

-(void)animateExplosions{

  //배열에서 각각의 폭파 스프라이트를 꺼낸다.

  for (CCSprite *explosion in explosions) {

    //보이게 설정을 한다.

    explosion.visible = YES;

    //0.4 동안 3 커지게 설정

    CCScaleTo *scale = [CCScaleTo actionWithDuration:0.4 scale:3.0];

    //애니메이션이 끝나면 숨기고, 삭제한다.

    CCCallBlock *block = [CCCallBlock actionWithBlock:^{

        explosion.visible = NO;

        [self removeFromParentAndCleanup:YES];

    }];

    //움직임 에니메이션이 끝나면 block 순차적으로 실행하기 위한 시퀀시 생성

    CCSequence *seq = [CCSequence actions:scale, block, nil];

    [explosion runAction:seq];

  }

}


배열에서 각각의 스프라이트를 꺼낸 뒤, 보이게 설정하고, CCScaleTo 을 사용하여 특정 시간동안 스프라이트를 확대하는 액션을 생성한다. 그리고 애니메이션이 끝나면 숨기고, 삭제하는 블럭 타입의 콜백을 생성한다. 그리고 액션과 블럭 콜백을 순차적으로 실행하기 위해서 시퀀시를 생성한 후, 액션을 실행한다. 


플레이어 폭발 애니메이션을 간단하였지만, 총알과 적의 충돌시 샐행되는 먼지 효과 애니메이션을 살짝 복잡하다. 어렵지 않으니 차근차근 따라해보자. 우선 애니메이션을 위해서 animateDusts 메소드를 생성하고 아래코드를 붙여넣는다. 

-(void)animateDusts{

  //에니메이션을 위해서 먼지를 세팅

  for (CCSprite *dust in dusts) {

    //숨긴 이미지를 다시 보이게

    dust.visible = YES;

    

    //10개의 이미지의 크기를 랜덤으로 가져옴

    float scaleRandom = 0.1 + ( (double)arc4random() / (double)0xffffffff );

    //0.3 시간동안 크기 변경 에니메이션

    CCScaleTo *scale = [CCScaleTo actionWithDuration:0.3 scale:scaleRandom];

    

    // 터지는 x위치를 위해서 랜덤 1 or -1

    int x = ( (double)arc4random() / (double)0xffffffff ) < 0.5 ? -1 : +1;

    float xRandom = 5 + 4 * ( ((double)arc4random()/(double)0xffffffff) * 10 * x );

    // 터지는 y위치를 위해서 랜덤 1 or -1  

    int y = ( (double)arc4random() / (double)0xffffffff ) < 0.5 ? -1 : +1;

    float yRandom = -30 + 4 * ( ((double)arc4random() / (double)0xffffffff ) * 10 * y );

    //0.3 시간동안 위치 변경 에니메이션

    CCMoveTo *move = [CCMoveTo actionWithDuration:0.3 position:ccp(xRandom, yRandom)];


    //에니메이션이 끝나면 숨기고 자신은 삭제를 위해서 블럭 함수 생성

    CCCallBlock *block = [CCCallBlock actionWithBlock:^{

        dust.visible = NO;

        [self removeFromParentAndCleanup:YES];

    }];

    //움직임 에니메이션이 끝나면 block 순차적으로 실행하기 위한 시퀀시 생성

    CCSequence *seq = [CCSequence actions:move, block, nil];

    //runAction 연이어 하면 동시에 크기와 움직임 엑션이 일어난다.

    [dust runAction:scale];

    [dust runAction:seq];

  }

}

기본 원리는 플레이어 폭발 애니메이션과 동일하다. 추가적으로 CCMoveTo를 사용해서 가운데서 터져서 양사방으로 움직이는 효과가 들어간다. 우선 숨겼던 이미지를 보이고 10개의 이미지가 모두 다른 크기로 커지게 하기 위해서 랜덤값을 생성한다. 그리고 CCScaleTo를 사용하여 0.3초 동안 확대한다. 그리고 10개의 이미지 모두 터지면 적의 중심으로 양사방으로 움직이게 하기위해서 x, y좌표를 랜덤으로 설정한다. 그리고 CCMoveTo를 사용해서 이동시킨다. 그리고 애니메이션이 끝나면 숨기고, 삭제하는 블럭 타입의 콜백을 생성한다. 그리고 액션과 블럭 콜백을 순차적으로 실행하기 위해서 시퀀시를 생성한 후, 액션을 실행한다. 


먼지 스프라이트 클래스는 완성되었다. 적용을 하기 위해서 GameLayer.m 로 이동한다. 

상단에 아래 코드를 추가하여서 클래스를 추가할 수 있도록 한다. 

#import "Dust.h"


총알과 적이 충돌해서 적의 에너지가 0 일때를 체크해서 폭발하는 효과 애니메이션을 실행할 것이. update:(ccTime)dt 에서 //미사일로 적을 공격해서 0점을 받아오는지를 체크하는 부분안에 아래 코드를 추가한다. 

- (void)update:(ccTime)dt {

...

  //미사일로 적을 공격해서 0점을 받아오는지를 체크

  if (![enemy attackedWithPoint:[bullet bulletType]]){


    //적이 폭파되면 먼지를 뿌려주기위한 노드 생성

    Dust *dust = [Dust node];

    //위치는 적이 폭파한 위치

    dust.position = enemy.position;

    //화면에 뿌려주기 위해 자식노드로 추가

    [self addChild:dust];

    //폭파하는 에니메이션 실행

    [dust animateDusts];

  }


...

}

적의 에너지가 0 이면 폭발 스프라이트 노드를 생성하고 적의 현재 위치에 먼지를 배치하고 난뒤에 폭발하는 애니메이션을 실행한다.


그리고 적과 플레이어가 충돌했을 경우에는 update:(ccTime)dt //적과 플레이어가 충동하는지를 체크하는 부분의 미사일을 없에는 부분 바로 밑에 아래 코드를 추가한다. 

- (void)update:(ccTime)dt {

...

        //적과 플레이어 케릭터가 충돌하는지를 체크

        if (!isCollision && CGRectIntersectsRect(enemy.boundingBox, _player.boundingBox)) {

            isCollision = YES;

            if (isCollision){

                _player.visible = NO;

                // 충돌하게 되면 마사일을 없엔다.

                [self unschedule:@selector(updateBullet)];

                for (Bullet *bullet in bulletsArray) {

                    bullet.visible = NO;

                    [bullet removeFromParentAndCleanup:YES];

                }

                

                //적이 폭발되면 먼지를 뿌려주기위한 노드 생성

                Dust *dust = [Dust node];

                //위치는 적이 폭발된 위치

                dust.position = _player.position;

                //화면에 뿌려주기 위해 자식노드로 추가

                [self addChild:dust z:1000];

                //폭발하는 에니메이션 실행

                [dust animateExplosions];

             ...
         }
...
}

적과 충돌을 하게 되면 폭발 노드를 생성하고 사용자 케릭터 배치시키고 폭발하는 애니메이션을 실행한다. 


Cmd(⌘) + R을 눌러서 실행을 해보자. 

총알과 적이 충돌할 경우, 플레이어 케릭터와 적이 충돌할 경우 폭발하는 애니메이션이 실행되는 것을 확인 할 수 있다. 


기본적인 게임 구현은 모두 끝났다. 다음 파트에서는 배경음악 재생과 총알과 적이 충돌했을 때 효과음, 적이 폭발할 때 효과음을 재생하는 것을 구현하도록 하겠다. 

Posted by KraZYeom

댓글을 달아 주세요