이미지를 미리 다 올려 두면 화면 전환이 부드럽다. 그렇게 안 했다.
Table of contents
Open Table of contents
두 방식을 재 봤다
방식이 둘이었다.
1. 시작할 때 CCTextureCache 에 전부 올린다 화면 전환이 빠르다. 메모리를 많이 쓴다
2. 화면마다 그때 올린다 화면 전환에 잠깐 멈춘다. 메모리를 적게 쓴다
1번이 빠르다. CCTextureCache 에 한 번 올려 두면 다시 읽지 않기 때문이다. 그래서 1번으로 하려고 기기 다섯 대에서 재 봤다.
기기 A 여유 있음
기기 B 여유 있음
기기 C 가끔 죽음 ←
기기 D 여유 있음
기기 E 자주 죽음 ←
둘에서 메모리가 모자랐다. 셋에서는 여유가 있었으니 내 기기만 봤으면 문제를 못 봤을 것이다.
무엇이 더 나쁜지로 골랐다
화면 전환에 0.3초 멈추는 것과 가끔 앱이 죽는 것을 놓고 봤다.
느린 것은 불편하고 죽는 것은 하던 것을 잃는다. 무게가 다르다. 빠르기로 고르면 앞이 이기지만 나쁜 정도로 고르면 뒤가 진다. 2번으로 했다.
단점을 줄이고 지우는 자리를 만들었다
정하고 나서 그 단점을 줄이는 작업을 했다.
void GameLayer::onEnterTransitionDidFinish() {
CCLayer::onEnterTransitionDidFinish();
preloadNextStage(); // 다음 스테이지 것을 뒤에서 올린다
}
onEnterTransitionDidFinish() 는 전환이 끝난 뒤에 불린다. 거기서 preloadNextStage() 를 부르면 사용자가 화면을 보는 동안 다음 것이 준비된다.
전환 화면도 넣었다.
CCScene* loading = LoadingScene::create(nextScene);
CCDirector::sharedDirector()->replaceScene(loading);
LoadingScene 을 만들어 CCDirector 의 replaceScene() 으로 먼저 띄운다. 멈춰 있는 것과 무언가 도는 것이 보이는 것은 다르게 느껴진다.
그다음에는 실제로 얼마나 쓰는지 계속 봤다.
void logMemory(const char* tag) {
CCTextureCache* cache = CCTextureCache::sharedTextureCache();
CCLOG("[mem] %s textures=%d", tag, cache->snapshotTextures()->count());
}
snapshotTextures() 의 개수를 CCLOG 로 찍는 logMemory() 를 넣고 화면을 옮길 때마다 봤다. 안 지워지는 것이 쌓이는 것이 그때 보였다.
[mem] title textures=12
[mem] stage1 textures=41
[mem] title textures=41 ← 스테이지 것이 안 지워졌다
그래서 지우는 자리를 만들었다.
void GameLayer::onExit() {
CCLayer::onExit();
CCTextureCache::sharedTextureCache()->removeUnusedTextures();
}
removeUnusedTextures() 를 안 부르면 2번으로 해도 메모리가 는다. 방식을 바꾸는 것만으로 안 되고 지우는 것을 같이 해야 했다.
이미지만 보고 있었는데 소리도 같은 문제였다.
SimpleAudioEngine::sharedEngine()->preloadEffect("hit.wav");
CocosDenshion 의 SimpleAudioEngine 으로 효과음 40개를 시작할 때 전부 올리고 있었다. 이 함수는 압축된 파일을 wave 로 풀어서 내부 버퍼에 넣으므로 파일이 작아도 올라간 크기는 작지 않다.
void SoundManager::preloadForScene(const std::string& scene) {
const std::vector<std::string>& list = s_sceneSfx[scene];
for (size_t i = 0; i < list.size(); i++) {
SimpleAudioEngine::sharedEngine()->preloadEffect(list[i].c_str());
}
}
이미지와 같은 방식으로 SoundManager::preloadForScene() 을 두어 화면별로 나누고 나갈 때 unloadEffect() 를 부르게 했다. 한 가지를 고치면 같은 이유로 만들어진 다른 것도 같이 본다.
결정 — 이유와 다시 볼 조건
나중에 미리 다 올리면 빠를 텐데라는 말이 나올 것이라 이유를 적어 뒀다.
리소스 로딩 방식
화면마다 올리는 방식으로 한다.
전부 미리 올리면 전환이 빠르지만 지원 기기 중 2대에서 메모리가 모자라 죽는다.
전환 0.3초와 앱이 죽는 것 중 죽는 것이 나쁘다고 보았다.
다시 볼 조건
- 지원 기기 목록에서 메모리 적은 기기가 빠질 때
- 화면 전환이 0.3초보다 오래 걸리게 될 때
어느 기기에서 죽었는지도 적었다. 나중에 그 기기를 다시 구하기 어렵다.
메모리 부족으로 죽은 기기
기기 C (RAM 512MB)
기기 E (RAM 384MB)
숫자가 있으니 새 기기를 받았을 때 재 볼지 말지 바로 갈린다.
정리
- 빠른 쪽이 항상 고를 쪽은 아니다. 무엇이 더 나쁜지로 고른다
- 느린 것은 불편하고 죽는 것은 하던 것을 잃는다
- 내 기기만 보면 문제를 못 본다. 다섯 대 중 둘에서만 죽었다
- 정하고 나서 그 단점을 줄이는 것을 한다
- 실제로 얼마나 쓰는지 재고 다닌다. 안 지워지는 것이 쌓이는 것이 그때 보인다
removeUnusedTextures()를 같이 넣어야 값이 유지된다preloadEffect()는 압축을 풀어 담으므로 파일 크기와 다르다- 고른 이유와 다시 볼 조건을 적는다
- 어느 기기에서 어땠는지 숫자로 남긴다. 나중에 그 기기를 못 구한다