SpriteKit SKTextureAtlas, Завершено из-за давления памяти при загрузке текстуры

Как и в популярной игре SpriteKit "Приключение" от WWDC, я пытаюсь загрузить свое фоновое изображение с помощью плиток. Я создал текстурный атлас, который содержит 6300 "плиток" размером 100x100 пикселей каждая. Полное фоновое изображение - 30 000x2048 (для дисплеев сетчатки). Идея в том, что фон будет перемещаться справа налево (боковой скроллер). Первый и последний столбцы совпадают, поэтому они кажутся непрерывными.

Когда приложение запускается, оно загружает мой начальный экран загрузки и изображения заголовков и всплески до 54 МБ на моей вкладке памяти с использованием ЦП 16%. Это остается тем же самым, как я перемещаюсь по меню, пока я не выберу свой уровень, который сообщает фоновому потоку, чтобы загрузить активы уровня (из которых содержит вышеупомянутое фоновое изображение). Вся папка.atlas показывает только 35,4 МБ. Я не верю, что это проблема, поскольку папка Adventure .atlas (из WWDC) имеет размер всего 32,7 МБ.

После того, как я выбрал уровень, он загружает примерно 20 текстур в папке.atlas, прежде чем начать получать предупреждения о памяти, и он вылетает из приложения. Я проверил в инструментах на утечки, и он не показывает утечек памяти. Я не получаю никаких ошибок компилятора (даже не EXC_BAD_ACCESS). Я посмотрел на консоль своего устройства и обнаружил несколько строк, в которых происходит сбой приложения, но для меня это не имеет особого смысла. Я также проверил зомби, но, похоже, не нашел ни одного.

CoreLevel.m

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
    // Used to determine time spent to load
    NSDate *startDate = [NSDate date];

    // Atlas to load
    SKTextureAtlas *tileAtlas = [SKTextureAtlas atlasNamed:@"Day"];

    // Make sure the array is empty, before storing the tiles
    sBackgroundTiles = nil;
    sBackgroundTiles = [[NSMutableArray alloc] initWithCapacity:6300];

    // For each row (21 Totals Rows)
    for (int y = 0; y < 21; y++) {

        // For each Column (100 Total Columns)
        for (int x = 1; x <= 100; x++) {

            // Get the tile number (0 * 32) + 0;
            int tileNumber = (y * 300) + x;

            // Create a SpriteNode of that tile
            SKSpriteNode *tileNode = [SKSpriteNode spriteNodeWithTexture:[tileAtlas               textureNamed:[NSString stringWithFormat:@"tile_%d.png", tileNumber]]];

            // Position the SpriteNode
            CGPoint position = CGPointMake((x * 100), (y * 100));
            tileNode.position = position;

            // At layer
            tileNode.zPosition = -1.0f;
            tileNode.blendMode = SKBlendModeReplace;

            // Add to array
            [(NSMutableArray *)sBackgroundTiles addObject:tileNode];
        }
    }
    NSLog(@"Loaded all world tiles in %f seconds", [[NSDate date] timeIntervalSinceDate:startDate]);
});

Вот что, похоже, относится к падению с консоли Debug:

com.apple.debugserver-300.2[9438] <Warning>: 1 +0.000000 sec [24de/1807]: error: ::read ( -1, 0x4069ec, 18446744069414585344 ) => -1 err = Bad file descriptor (0x00000009)
com.apple.debugserver-300.2[9438] <Warning>: Exiting.
com.apple.launchd[1] (UIKitApplication:tv.thebasement.Coin-Voyage[0x641d][9441]) <Notice>:     (UIKitApplication:tv.thebasement.Coin-Voyage[0x641d]) Exited: Killed: 9

У меня недостаточно репутации, чтобы размещать изображения, поэтому вот ссылка на скриншот с моим распределением в инструментах:

http://postimg.org/image/j17xl39et/

Любая помощь и совет высоко ценится! Если я пропустил некоторую соответствующую информацию, я рад обновить.

1 ответ

Решение

Размер файла изображения (PNG, JPG, папка Atlas и т. Д.) Ничего не говорит об использовании памяти.

Вместо этого вы должны рассчитать использование памяти текстуры по формуле:

width * height * (color bit depth / 8) = texture size in bytes

Например, изображение с размерами 4096x4096 пикселей и глубиной цвета 32 бита (4 байта) использует этот объем памяти при загрузке в качестве текстуры (без сжатия):

4096 * 4096 * 4 = 67108864 bytes (64 Megabytes)

Согласно вашим спецификациям (6300 плиток, каждый размером 100x100 пикселей, при условии, что все они уникальны), вы намного выше любого разумного предела использования памяти текстур (около 1,5 гигабайт!). Учитывая размер атласа 35 мегабайт (что огромно для атласа между прочим) и допуская степень сжатия 10:1, вы все равно можете использовать 350+ мегабайт памяти текстур.

Другие вопросы по тегам