SpriteKit SKTextureAtlas,在加载纹理时因内存压力而终止

时间:2014-02-13 20:24:54

标签: ios objective-c memory sprite-kit sktextureatlas

与WWDC的SpriteKit精选游戏“冒险”类似,我尝试通过磁贴加载我的背景图像。我创建了一个纹理图集,其中包含6,300个“图块”,每个图块的大小为100x100像素。完整的背景图像总共为30,000x2048(用于视网膜显示)。想法是背景将从右向左移动(侧卷轴)。第一列和最后一列匹配,以便它们看起来是连续的。

当应用程序运行时,它会在我的内存选项卡中加载我的初始加载屏幕和标题图像以及峰值 54MB ,CPU使用率 16%。这与我浏览菜单时保持不变,直到我选择我的级别,这告诉后台线程加载级别资产(其中包含上述背景图像)。整个.atlas文件夹只显示 35.4MB 。我不相信这是一个问题,因为Adventure .atlas文件夹(来自WWDC)显示只有 32.7MB

一旦我选择了关卡,它会在我开始接收内存警告并且崩溃应用程序之前加载.atlas文件夹中大约20个纹理。我已经检查了仪器的泄漏,并没有显示任何内存泄漏。我没有收到任何编译器错误(甚至没有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]);
});

这似乎与调试控制台崩溃有关:

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 个答案:

答案 0 :(得分:3)

图像文件(PNG,JPG,atlas文件夹等)的文件大小不会告诉您有关内存使用情况的信息。

相反,您必须使用以下公式计算纹理内存使用情况:

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

例如,尺寸为4096x4096像素和32位颜色深度(4字节)的图像在作为纹理(未压缩)加载时会使用这么多内存:

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

根据你的规格(6,300个瓷砖,每个100x100像素,假设它们都是独一无二的)你的方式,比任何合理的纹理内存使用限制(大约1.5千兆字节!)更方便。考虑到地图集大小为35兆字节(对于地图集btw而言巨大)并且假设压缩比仅为10:1,您可能仍然需要350+兆字节的纹理内存使用量。