cocos2d-x 를 고를 때 가장 크게 들린 말이 있었다. 코드 하나로 Android 와 iOS 를 함께 낸다는 것이다. 실제로 그랬다. 그런데 프로젝트가 끝날 때쯤 세어 보니 플랫폼별 분기가 생각보다 많았다.
Table of contents
Open Table of contents
결과 — 정말로 공유되던 것
먼저 공유가 잘 된 부분을 적어 둔다. 이건 약속대로였다.
- 게임 규칙과 계산
- 아이템·인벤토리 같은 자료구조
- 화면에 무엇을 어디에 그릴지
- 서버와 주고받는 형식
여기까지는 한 번 만들면 양쪽에서 똑같이 돌았다. 전체 코드의 대부분이었고 그 점에서 엔진은 약속을 지켰다.
빌드가 달랐다
코드가 같아도 빌드 방법은 완전히 달랐다. iOS 는 Xcode 로만 되고 Android 는 ndk-build 를 거친다. 그 시절 NDK 는 윈도우에서 Cygwin 을 깔아야 돌았다.
r7 에 ndk-build.cmd 가 붙어 Cygwin 없이도 빌드는 됐다. 다만 실험 단계였고 ndk-gdb 는 여전히 윈도우에서 못 썼다. 그래서 결국 깔게 됐다.
거기서 경로가 어긋났다.
# 윈도우 경로
C:\project\Classes
# 빌드 스크립트가 기대하는 형태
/cygdrive/c/project/Classes
스크립트를 복사해 오면 이런 게 맞지 않았다. 처음에는 왜 안 되는지 몰라서 오타를 찾았다.
개행 문자도 그랬다. 윈도우에서 만든 스크립트를 그대로 쓰면 줄 끝에 \r 이 붙어 명령이 실패했다. 눈에 안 보이는 차이 때문에 며칠을 썼다.
텍스트와 화면 크기가 달랐다
한글이 Android 에서만 깨졌다. 같은 코드에 같은 지정인데 iOS 는 멀쩡했다.
원인을 좁히는 데 오래 걸렸다. CCLabelTTF 는 기기의 폰트를 쓴다. 기기마다 기본 폰트가 다르고 그 폰트에 그 글자가 없으면 안 나온다. .ttf 를 앱에 넣고 그것만 쓰게 하는 것이 유일하게 확실한 방법이었다. 용량은 늘었다.
화면 크기도 그랬다. iOS 는 기기 종류가 적고 Android 는 많았다. 같은 좌표로 배치하면 어떤 기기에서는 버튼이 화면 밖으로 나갔다. 해상도만 다른 것이 아니라 가로세로 비율이 달랐다.
처음에는 기기별로 분기를 넣었다. 기기가 늘수록 분기도 늘었다. 이때 판에는 기준 해상도를 잡아 주는 것이 없어서 getWinSize() 를 받아 비율로 배치하는 틀을 직접 만들었다. 이걸 처음부터 했어야 했다.
뒤로 가기 버튼은 흐름의 문제였다
Android 에는 뒤로 가기 버튼이 있고 iOS 에는 없다. 이건 화면 배치가 아니라 흐름의 문제였다.
CCKeypadDelegate 에 keyBackClicked() 가 있다. 안 받으면 기본 동작으로 앱이 그냥 종료된다. 게임 도중에 실수로 누른 사람의 진행이 그대로 날아갔다. 이 하나 때문에 화면마다 여기서 뒤로 가면 어디로 가는지를 정해야 했다. iOS 에는 없는 개념이라 공유 코드에 넣을 수 없었다.
세어 보지는 않았지만 체감으로는 이랬다.
| 공유 여부 | |
|---|---|
| 게임 로직 | 거의 전부 |
| 화면 구성 | 대부분 (좌표 계산은 분기) |
| 입력 처리 | 대부분 (뒤로 가기는 분기) |
| 폰트·텍스트 | 분기 |
| 빌드·배포 | 공유 없음 |
| 스토어 대응 | 공유 없음 |
공유가 안 되는 것은 대부분 플랫폼이 정한 것이었다. 빌드 방식과 입력 방식과 배포 절차다.
코드 하나로 두 플랫폼이라는 말을 코드 전체가 하나라는 뜻으로 들은 것이 오해였다. 정확히는 내가 쓰는 로직을 하나로 둘 수 있다는 뜻이었다. 로직은 한 번 만들면 되지만 플랫폼 대응은 플랫폼 수만큼 든다.
정리
- 로직은 정말로 공유되고 코드의 대부분이 여기 해당한다
- 공유되지 않는 것은 플랫폼이 정한 것들이다
Xcode와ndk-build는 빌드 방식 자체가 다르다- 윈도우에서
NDK를 쓰려면 그 시절엔Cygwin이 필요했다 - 경로 구분자와 개행 문자
\r처럼 눈에 안 보이는 것이 오래 걸렸다 CCLabelTTF는 기기 폰트를 쓰므로.ttf를 넣고 지정한다- 기기 종류가 많은 쪽에서 먼저 깨진다
- 기준 하나를 잡고
getWinSize()로 비율을 맞추는 편이 분기보다 낫다 keyBackClicked()를 안 받으면 앱이 그냥 종료된다