iDev/Cocos2D

드래곤 플라이트 따라 만들기 - 6. 충돌 처리 및 적 게이지

KraZYeom 2013. 1. 31. 08:43
반응형

이번 파트에서는 총알과 플레이어 충돌,  적과 플레이어 충돌 그리고 적의 에너지 게이지 추가를 구현하겠다. 


총알과 플레이어 케릭터 충돌처리


총알과 플레이어 케릭터의 충돌처리는 아주 간단하다. 플레이어 스프라이트의 바운딩 박스 영역과 총알 스프라이트의 바운딩 박스의 영역이 겹치면 충돌했다고 처리하면 된다. 물론 더 세세한 충돌처리를 위해서는 케릭터의 모양을 여러 개의 영역으로 나눠서 충돌했는지를 체크하거나, 더 정확하게 하려면 플레이어 케릭트 외곽선을 전부 따서 하는 방법도 있다. 여러가지 방법이 있긴 하지만 가장 간단한 방법을 선택하도록 한다. 

gameLayer.h 에 이동하여 충돌하였는지를 체크 할수 있게 변수하나를 추가한다. 

    BOOL isCollision;


충돌 처리를 위해서 gameLayer.m으로 이동해서 - (void)update:(ccTime)dt  메소드에 아래 코드를 추가한다.   

  //총알 플레이어와 케릭터 충돌을 위해서 배열에서 적을 하나 꺼낸다.

for (Enemy *enemy in enemysArray) {

    //적이 죽은 상태이면 그냥 넘어간다.

    if (!enemy.state) continue;

    

    //총알을 하나 배열에서 꺼낸다

    for (Bullet *bullet in bulletsArray) {

        //총알이 적에 맞아서 없어진 상태면 그냥 넘어간다.

        if (!bullet.visible) continue;

        

        //총알과 적이 충돌이 나는지를 체크

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

            //총알을 없애고

            bullet.visible = NO;

            //싸운드 효과를 재생한다.

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

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

                //싸운드 효과를 재생한다.

                //적이 폭파되면 먼지를 뿌려주기위한 에니메이션

            }

        }

    }

}
적을 담고 있는 배열에서 적을 꺼내서 죽었는지 상태 체크를 하고, 죽지 않았으면 총알의 배열에서 총알을 꺼내서 총알이 맞아서 없어진 상태인지를 체크 한다. 그리고 CGRectIntersectsRect(CGRect rect1, CGRect rect2)메소드를 통해서 두개의 영역이 겹쳤는지를 체크 한다. 충돌이 일어났으면 총알을 없애고, 총알 타입에 따른 적이 얼마나 피해를 입었는지를 체크 한다. 

총알에 따라서 적이 얼마나 피해를 입었는지 체크를 위해서 Enemy.h 로 이동해서 아래 코드를 추가한다. 

-(NSInteger)attackedWithPoint:(NSInteger)point;


Enemy.m으로 이동해서 아래 코드를 추가한다. 

-(NSInteger)attackedWithPoint:(NSInteger)point {

    //공격 받은 숫자 만큼 에너지를 줄여준다.

    _energy -= point;

    //0미만으로 되면 0 아니면 현재 에너지를 반환

    if ( _energy <= 0 ) {

        //죽으면 숨긴다

        [self destroy];

    }

    return _energy;

}


-(void)destroy {

    //적이 죽으면 상태 값을 변경

    _state = kDestoryed;

    //에너지는 0으로 한다.

    _energy = 0;

    //그리고 숨긴다.

    self.visible = NO;

}

미사일의 포인트 만큼 적의 에너지를 줄이고, 0이하가 되면 적을 죽인다. 상태값을 죽은 상태로 하고 에너지는 0, 그리고 숨긴다.  

적과 플레이어 케릭터 충돌처리

적과 플레이어 케릭터 충돌처리도 간단하다. 총알과 적과 충돌처리처럼 겹치는 영역이 있으면 충돌처리를 하고 게임을 끝나게 하면 된다. 


gameLayer.m 에서 위에 추가한 for (Enemy *enemy in enemysArray) {} 괄호 안에서 마지막에 아래 코드를 추가한다. 


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

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];

        }

        

        CCCallBlock *allStop = [CCCallBlock actionWithBlock:^{

            //터치 이벤트를 더이상 받지 않는다.

            self.isTouchEnabled = NO;

        }];

        //딜레이를 위한 엑션

        CCDelayTime *delay = [CCDelayTime actionWithDuration:2.0f];

        //딜레이후 메뉴로 나가기 위한 엑션 블럭

        CCCallBlock *block = [CCCallBlock actionWithBlock:^{

            //메뉴 레이어로 돌아간다.

            [[CCDirector sharedDirector] replaceScene:[MenuLayer scene]];

        }];

        //엑션을 순서대로 준비.

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

        //엑션 실행

        [self runAction:seq];

    }

}

메소드가 짧은 시간에 여러번 호출 되기 때문에 충돌이 났는지 나지 않았는지를 체크한다. 충돌이 없는 상태에서 영역이 겹치게 되면, 충돌 체크를 하고 총알 스케줄러를 멈춰서 더 이상 총알이 나가지 않게 한다. 콜백 블럭에 터치를 받지 않게 처리하고, 바로 끝나면 이상하므로 2초간 게임화면이 보이게 한다. 그리고 다시 콜백 블럭으로 메뉴 화면으로 빠져 나가게 한다. 이 3개의 엑션들을 순차적으로 액션처리 한다. 

모든 게임 기본 기능은 다 구현 되었다. 그런데 적이 총알을 맞았는데 얼마만큼 에너지가 줄었는지 체크를 해야 한다. 적의 하단에 에너지 게이지를 추가 하도록 하겠다. 

CCNode를 상속받아서 EnegyGauge라는 클래스를 추가한다 
그리고 EnergyGauge.h에 아래 코드를 추가한다. 

@interface EnergyGauge : CCNode {

    CGFloat maxValue;

    CGFloat currentValue;

    CGSize maxSize;

}

+ (id)initWithMaxSize:(CGSize)size maxValue:(CGFloat)_maxValue;

- (id)initWithMaxSize:(CGSize)size maxValue:(CGFloat)maxVal;

- (void)updateBar:(CGFloat)_currentValue;

게이지의 최대값, 현재값 그리고 최대 크기를 저장하는 변수를 생성하고, 생성하는 메소드와 외부에서 게이지바를 변경할 수 있게 해주는 메소드를 추가한다. 

EnergyGauge.m으로 이동해서 생성 관련 메소드를 아래와 같이 추가하여 작성한다. 

+(id)initWithMaxSize:(CGSize)size maxValue:(CGFloat)_maxValue{

     return [[self alloc] initWithMaxSize:size maxValue:_maxValue];

}


- (id)initWithMaxSize:(CGSize)size maxValue:(CGFloat)_maxValue{

    self = [super init];

    if ( self ){

        maxSize = size;

        currentValue = maxValue = _maxValue;

    }

    return self;

}



에너지 게이지를 스프라이트를 사용해서 그릴수도 있지만 간단하게 OpenGL을 이용해서 그리도록 한다. 아래 코드를 복사, 붙여 넣기한다. 

- (void)draw{

    //최대값 기준으로 % 환산한 너비

    CGFloat width = (currentValue / maxValue) * (float)maxSize.width;

    //라인의 두깨는 높이값이다.

    glLineWidth(maxSize.height);

    //100% 때는 Green

    if (currentValue == maxValue) {

        ccDrawColor4B(255, 255, 0, 255);

    // 외에는 Red

    } else {

        ccDrawColor4B(255, 0, 0, 255);

    }

    //선을 그린다.

    ccDrawLine(ccp(0, 0), ccp(width, 0));

}

너비 값을 구하고, 게이지의 두깨를 설정한다. 그리고 최대 값일때는 노란색(배경색이 초록색이여서 노락색으로 변경함), 아닐 경우에는 빨간색으로 설정한다. 그리고 길이, 두깨 만큼 선을 그린다. 

외부에서 게이지바의 업데이트 하기 위해 아래 코드를 추가한다. 

- (void)updateBar:(CGFloat)_currentValue{

    //값을 값을 현재 값으로 할당한다.

    currentValue = _currentValue;

    //0 이하면 0으로, 최대값을 초과하면 최대값으로 보정한다.

    if (currentValue < 0 ) currentValue = 0;

    else if (currentValue > maxValue) currentValue = maxValue;

}

현재 값을 할당하고, 0미만이면 0으로 설정하고 최대 값을 벗어 나면 최대값으로 설정한다. 

적에게 게이지를 추가하기 위해서 Enemy.h로 이동해서 프로퍼티를 아래와 같이 추가한다. 

@property (nonatomic, strong) EnergyGauge *gauge;


그리고 - (id)init 메소드 아래에 다음 코드를 추가한다. 

        //에너지 게이지 객채를 생성한다

        _gauge = [EnergyGauge initWithMaxSize:CGSizeMake(self.boundingBox.size.width, 10) maxValue:100];

        //에너지 게이지를 자식으로 추가.

        [self addChild:_gauge];

게이지 객체를 너비와 높이값 그리고 최대 값으로 생성한다. 그리고 자식으로 추가한다. 

적이 공격을 받았을 경우 처리를 하기 위해서 -(NSInteger)attackedWithPoint:(NSInteger)point 메소드 안 _energy -= point; 코드 아래에 다음 코드를 추가한다.

    //게이지 업데이트

    [_gauge updateBar:_energy];



그리고 적이 초기화 되었을 때 에너지 게이지를 초기화 하기 위해서  -(void)reset 메소드 가장 아래 부분에 다음 코드를 추가한다 

    //죽어서 안보이던 적을 다시 보여준다.

    [self setVisible:YES];

    //상태값을 일반 상태로 변경 한다.

    _state = kNormal;



    //게이지 바를 초기화 한다.

    [_gauge updateBar:_energy];



Cmd(⌘) + R 해서 Run을 해보자. 총알과 적이 충돌을 하면 에너지가 줄어드는 모습을 볼 수 있고, 이리저리 움직이다가 적과 충돌을 하게 되면 게임이 종료되는 것을 확인 할 수 있다. 

기본적 게임 기능은 모두 추가 되었다. 다음 파트에서는 점수를 나타내는 HUD 추가와 폭파할때 일어나는 에니메이션 등을 구현 하도록 하겠다. 


시뮬레이터 상에서 스프라이트 이미지가 많이지면서 프레임 레이트가 20 밑으로 뚝뚝 떨어지는 것을 볼 수 있다. 실제 기기 상에서는 문제 없이 나온다. 시뮬레이터와 단말기에서 사용하는 OpenGL 이 달라서 그렇다. 

반응형