프로그래밍/Cocos2D2010. 7. 2. 17:55
충돌 검사
이전 포스트까지의 내용대로 개발된 게임은 아무리 총알을 발사해도 타겟을 통과할 뿐이다. 이 문제를 해결하기 위해 충돌 검사라는 것이 필요하다.

케익에 맞은 맘모스는 게임 화면에서 사라져와 한다. 물론 잘 만들어진 게임이라면 총알 맞는 효과 같은 것들이 부수적으로 필요할 것이다. 

그러나 간단한 게임 예제라는 전제로 이런 부분들은 배제하고 간단히 총알과 타겟이 만났을 경우만 처리하는 코드를 작성할 것이다. 게임 물리의 거리, 운동 등의 다양한 면을 담당하는 게임 엔진의 한 부분인 물리 엔진은 사용되지 않는다.

먼저 다음 코드를 MammothHuntingScene.h에 추가하자.

NSMutableArray *_targets;

NSMutableArray *_projectiles;


그리고 MammothHuntingScene.m의 init 메소드의 self.isTouchEnabled = YES; 아래에 다음 코드를 추가한다.

_targets = [[NSMutableArray allocinit];

_projectiles = [[NSMutableArray allocinit];


마지막으로 메모리 관리를 위해 MammothHuntingScene.m의 dealloc 메소드에 다음 코드를 추가한다.

[_targets release];

_targets = nil;

[_projectiles release];

_projectiles = nil;


이제 addTarget 메소드르 수정할 차례이다. 위에서 선언한 _targets 배열에 새로운 target를 추가하는 것이다. 제일 아랫 부분에 다음처럼 추가하자. 새로 설정한 tag는 나중에 사용될 것이다.

target.tag = 1;

[_targets addObject:target];


그리고 ccTouchesEnded 메소드 역시 _projectiles 배열에 새로운 projectile을 추가하게 끔 다음 코드를 메소드 마지막에 추가한다. 새로 설정한 tag는 나중에 사용될 것이다.

projectile.tag = 2;

[_projectiles addObject:projectile];


마지막으로 spriteMoveFinished 메소드에 위에서 설정한 tag를 기반으로 스프라이트를 삭제하는 코드를 추가한다.

if (sprite.tag == 1) { // 타겟.

[_targets removeObject:sprite];

else if (sprite.tag == 2) { // 총알.

[_projectiles removeObject:sprite];

}


빌드앤런 해보자. 그런데 이전과 마찬가지로 실제 사냥이 되지는 않을 것이다. 당연하다. 충돌 검사 코드가 아직 작성되지 않았다. 다음 update: 메소드를 MammothHuntingScene.m에 추가해야 한다.

- (void)update:(ccTime)dt {

NSMutableArray *projectilesToDelete = [[NSMutableArray allocinit];

for (CCSprite *projectile in _projectiles) {

CGRect projectileRect = CGRectMake(

   projectile.position.x - (projectile.contentSize.width/2), 

   projectile.position.y - (projectile.contentSize.height/2), 

   projectile.contentSize.width

   projectile.contentSize.height);

NSMutableArray *targetsToDelete = [[NSMutableArray allocinit];

for (CCSprite *target in _targets) {

CGRect targetRect = CGRectMake(

   target.position.x - (target.contentSize.width/2), 

   target.position.y - (target.contentSize.height/2), 

   target.contentSize.width

   target.contentSize.height);

if (CGRectIntersectsRect(projectileRect, targetRect)) {

[targetsToDelete addObject:target];

}

}

for (CCSprite *target in targetsToDelete) {

[_targets removeObject:target];

[self removeChild:target cleanup:YES];

}

if (targetsToDelete.count > 0) {

[projectilesToDelete addObject:projectile];

}

[targetsToDelete release];

}

for (CCSprite *projectile in projectilesToDelete) {

[_projectiles removeObject:projectile];

[self removeChild:projectile cleanup:YES];

}

[projectilesToDelete release];

}


update: 메소드는 루프를 돌면서 총알과 타겟이 교차하는 지  CGRectIntersectsRect를 통해 검사한다. 만약 교차한다면 화면과 배열에서 제거해 버린다. 
여기서 한 가지 주의할 것이 있다. 충돌 검사 루프를 하는 동안은 배열의 객체를 삭제할 수 없으므로 제거 대상을 배열에 넣었다가 삭제한다.

정말 마지막으로 다음의 코드를 init 메소드 하단에 추가하고 빌드앤런하자. 이제 맘모스를 사냥할 수 있을 것이다.

[self schedule:@selector(update:)];


서두에 간단히 물리 엔진에 대해서 이야기 했던 것처럼, 간단한 그래픽 기반 게임 조차 어느 정도 물리 코드가 필요하다. 이 말은 충돌 검사의 다양한 방법이 있다는 것이다. 다음 기회에 Cocos2D의 물리 엔진인 Box2d와 Chipmunk를 공부할 항목에 추가해야 겠다.

---

Posted by windship