Skip to content
isdnetworks
Go back

예외 처리가 쌓여서 구조를 바꿨다

충돌 판정 함수에 조건문이 계속 붙었다. 어느 날 grep 으로 세어 보니 열한 개였다.

Table of contents

Open Table of contents

하나씩 붙은 것이었다

SVN 이력을 보려고 svn blame 을 걸어 보니 열한 줄이 서로 다른 날짜였다. 버그가 하나 올라올 때마다 한 줄씩 넣은 것이고 각각은 맞는 조건이었다.

if (a.type == TYPE_GHOST && b.type == TYPE_WALL) return false;
if (a.type == TYPE_ARROW && b.isDead) return false;
if (a.state == STATE_INVINCIBLE) return false;

문제는 새 조건을 넣을 때 앞의 열한 개와 부딪히는지 봐야 한다는 것이었다. 치유 스킬이 죽은 아군에게도 닿아야 한다는 요구가 들어왔을 때 화살만 막는 것처럼 보이던 줄이 치유도 막고 있었다. 어느 줄이 무엇을 막는지 알 수가 없었다.

무엇을 판단하는지로 나눴다

한 함수가 여러 가지를 판단하고 있었다. 닿을 수 있는 사이인지와 지금 닿을 수 있는지와 실제로 닿았는지 셋이다.

bool checkHit(const Unit& a, const Unit& b) {
    return canInteract(a, b) && isTargetable(b, a.hitKind) && isOverlapping(a, b);
}

canInteractisTargetableisOverlapping 셋으로 나눴다. 새 조건이 오면 어디에 넣을지가 먼저 갈린다. 조건을 넣기 전에 앞의 것을 전부 읽을 필요가 없어졌다.

표로 만들었다

첫 번째가 여전히 복잡해서 조건문 대신 static const 표로 만들었다. enum 이 이미 있으니 그것을 첨자로 쓰면 된다.

static const bool s_interact[TYPE_COUNT][TYPE_COUNT] = {
    /*            적    아군  벽    유령 */
    /* 공격 */  { true, false, true, true  },
    /* 치유 */  { false, true, false, false },
};

s_interact 표를 보면 전체가 한눈에 보이고 빠진 조합도 드러난다. 조건문이었을 때는 어떤 조합이 안 다뤄지는지 알 수 없었다. 배열 크기를 재서 TYPE_COUNT 와 맞는지 보게 했다. enum 에 값이 늘면 CCAssert 가 걸린다.

표가 맞는지 확인하는 것도 만들어서 CCAssert 로 걸었다. SVN 이력에서 찾은 열한 가지를 전부 넣으니 구조를 바꾸면서 옛 동작이 깨지지 않았는지가 그걸로 확인됐다.

언제 나눌지의 기준

늦게 바꿨다는 생각이 들어 기준을 적어 뒀다. 조건이 다섯을 넘으면 나눌 때로 본다. 새 조건을 넣을 때 앞의 조건을 전부 다시 읽어야 하면 그것이 신호다. 조건 하나를 넣는 데 30분씩 걸리고 있었으면 이미 늦은 것이었다.

나누면서 안 쓰이는 조건도 둘 찾았다. 함정과 아이템은 애초에 같은 화면에 안 나오는데 그 조합을 막는 줄이 남아 있었다. 한 번도 참이 안 되는 조건이었고 지웠다. 조건을 늘리기만 하고 지운 적이 없었던 것이다.

구조를 바꾼 값은 다음 요구에서 나왔다. 방어막이 화살은 막고 마법은 통과시킨다는 조건이 왔다. 표에서 한 칸이었고 5분에 끝났다. 전에는 30분씩 걸리던 일이다.

정리


Share this post on:

Previous Post
어느 사본이 진짜인지 몰랐다
Next Post
앱이 조금씩 죽어 갔다