적 체력을 조금 올려 달라는 요청을 받았다. 값을 찾는 데 이십 분이 걸렸다. .cpp 세 군데에 비슷한 숫자가 있었고 어느 것이 그 적인지 헷갈렸다.
Table of contents
Open Table of contents
숫자가 세 군데에 있었다
적 종류마다 체력을 정하는 곳이 Enemy.cpp 다. 스테이지에 따라 배율을 곱하는 곳은 Stage.cpp 다. 피해량을 계산하는 곳은 Battle.cpp 로 또 달랐다.
if (type == ENEMY_BAT) { hp = 30; speed = 120.0f; damage = 5; } // Enemy.cpp
if (stageNo >= 5) { enemyHp = enemyHp * 1.2f; } // Stage.cpp
int realDamage = damage - (defense / 2); // Battle.cpp
체력이 정해지는 데가 둘이다. 피해량 계산이 또 다른 곳이라 하나를 올려도 다른 데서 상쇄됐다.
조정할 때마다 빌드했다
숫자를 고치면 ndk-build 를 돌리고 기기에 올려야 했다. 한 번에 5 분쯤 걸렸다.
밸런스는 한 번에 안 맞는다. 조금 올리고 해 보고 또 조금 올린다. 열 번 조정하면 50 분이 ndk-build 다. 고치는 시간보다 확인하는 시간이 길면 조정을 덜 하게 된다. 그러면 밸런스가 대충 맞은 채로 굳는다.
파일로 뺐다
수치를 assets/enemy.txt 로 옮기고 읽는 코드를 만들었다.
# type hp speed damage
ENEMY_BAT 30 120 5
ENEMY_SLIME 50 60 8
읽는 것은 CCFileUtils::getFileData 다. fopen 을 바로 쓰면 안 된다. Android 는 이 파일이 APK 라는 zip 안에 있어서다.
안쪽을 열어 보니 갈림이 있었다. 경로가 / 로 시작하지 않으면 앞에 assets/ 를 붙여 APK 안에서 꺼낸다. / 로 시작하면 그냥 fopen 이다.
그래서 시험 빌드는 /sdcard/enemy.txt 를 먼저 보게 했다. adb push 로 밀어 넣고 다시 읽는 버튼을 누르면 반영된다. 빌드 5 분이 버튼 한 번이 됐다.
파일에서 읽으니 형식이 틀릴 수 있어서 읽는 시점에 확인하게 했다. atoi 는 글자가 들어와도 오류를 안 내고 0 을 돌려준다. strtol 로 바꾸고 endptr 이 어디서 멈췄는지를 봤다. 안 읽힌 줄은 몇 번째 줄이 왜 잘못됐는지 CCLOG 에 남기고 건너뛴다. 한 줄 때문에 전체가 안 뜨면 곤란하다.
파일로 뺄 것과 남길 것
전부 뺄 수 있는 것은 아니었다. Battle.cpp 의 피해량 계산은 값이 아니라 식이다. 파일로 빼려면 식을 해석하는 코드가 필요한데 그건 배보다 배꼽이다.
식에 든 숫자에만 이름을 붙여 BattleConst.h 한 곳에 모았다.
const float DEFENSE_RATE = 0.5f; // 방어력 반영 비율
const int MIN_DAMAGE = 1; // 최소 피해량
파일로 뺀 것은 아니지만 어디를 고칠지는 명확해졌다. 자주 조정하는 수치는 enemy.txt 에 둔다. 가끔 바꾸는 상수는 이름을 붙여 .h 에 둔다. 계산 방식은 .cpp 에 둔다. 전부 파일로 빼려다 형식이 복잡해지면 그것도 비용이다.
정리
- 조정할 값이 흩어져 있으면 한 곳을 고쳐도 다른 데서 상쇄된다
- 고치는 시간보다 확인하는 시간이 길면 조정을 덜 하게 된다
- 그러면 밸런스가 대충 맞은 채로 굳는다
- 자주 바꾸는 수치를
assets로 빼면ndk-build없이 반영된다 - 다시 읽는 기능을 두면 확인 시간이 더 줄어든다
- 파일은 형식이 틀릴 수 있으니 어느 줄이 왜 잘못됐는지 알려 준다
atoi는 실패해도 0 만 준다.strtol의endptr로 가른다- Android 는
assets가 APK 안이라fopen이 아니라getFileData로 읽는다 - 식은 코드에 두고 그 안의 숫자에만 이름을 붙인다