21

我正在制作游戏,我注意到在某些场景中,我的 FPS 一直在 55-60FPS 区域附近下降(使用纹理图集)。这让我发疯了,所以我决定把我所有的资产放到 Images.xcassets 文件夹中,瞧,稳定的 60FPS。

我认为这是侥幸或我做错了什么,所以我决定开始一个新项目并执行一些基准测试......


Apple 的文档说使用纹理图集将提高应用程序的性能。基本上,允许您的应用程序利用批量渲染。然而...

测试(https://github.com/JRam13/JSGlitch):

- (void)runTest
{
    SKAction *spawn = [SKAction runBlock:^{

        for (int i=0; i<10; i++) {


            SKSpriteNode *sprite = [SKSpriteNode spriteNodeWithImageNamed:@"Spaceship"];

            sprite.xScale = 0.5;
            sprite.yScale = 0.5;
            sprite.position = CGPointMake(0, [self randomNumberBetweenMin:0 andMax:768]);

            SKAction *action = [SKAction rotateByAngle:M_PI duration:1];

            [sprite runAction:[SKAction repeatActionForever:action]];

            SKAction *move = [SKAction moveByX:1200 y:0 duration:2];

            [sprite runAction:move];

            //notice I don't remove from parent (see test2 below)
            [self addChild:sprite];

        }

    }];

    SKAction *wait = [SKAction waitForDuration:.1];

    SKAction *sequence = [SKAction sequence:@[spawn,wait]];
    SKAction *repeat = [SKAction repeatActionForever:sequence];

    [self runAction:repeat];
}

结果:

在此处输入图像描述

反复测试表明,使用 xcassets 比 FPS 中的 atlas 表现更好。不过,atlas 似乎确实比 xcassets 管理内存稍好。

有谁知道为什么这些结果表明 images.xcassets 比图集有更好的性能?


我提出的一些假设:

  • xcassets 比 atlasas 优化得更好。
  • atlasas 擅长在一次绘制过程中绘制大量图像,但重复精灵的开销更大。如果为真,这意味着如果您的精灵多次出现在屏幕上(在我的原始游戏中就是这种情况),最好将其从图集中删除。
  • 必须填写地图集表以优化性能

更新

对于下一个测试,我继续并在它离开屏幕后从父级中删除了精灵。我还使用了 7 个不同的图像。由于绘制次数,我们应该看到使用 atlas 的巨大性能提升,但是......

在此处输入图像描述

4

1 回答 1

16

首先,修改您的测试以匹配此:

    for (int i=0; i<10; i++) {


        SKSpriteNode *sprite = [SKSpriteNode spriteNodeWithImageNamed:@"Spaceship"];

        sprite.xScale = 0.5;
        sprite.yScale = 0.5;
        float spawnY = arc4random() % 768;
        sprite.position = CGPointMake(0, spawnY);

        SKAction *action = [SKAction rotateByAngle:M_PI duration:1];

        [sprite runAction:[SKAction repeatActionForever:action]];


        SKAction *move = [SKAction moveByX:1200 y:0 duration:2];

        // next three lines replace the runAction line for move
        SKAction *remove = [SKAction removeFromParent];
        SKAction *sequence = [SKAction sequence:@[move, remove]];
        [sprite runAction:sequence];

        [self addChild:sprite];

    }

重新运行你的测试,你应该注意到你的帧率永远不会像你的测试那样恶化。您的测试基本上说明了当您从不删除节点但继续创建新节点时会发生什么。

接下来,在设置 skview 时将以下行添加到 ViewController 中:

skView.showsDrawCount = YES;

这将允许您查看绘制计数并正确了解使用 SKTextureAtlas 提升性能的地方。

现在,不是只有一个图像,而是收集 3 个图像并通过在每次创建节点时选择其中一个随机图像来修改您的测试,您可以这样做:

 NSArray *imageNames = @[@"image-0", @"image-1", @"image-2"];
 NSString *imageName = imageNames[arc4random() % imageNames.count];

在您的代码中,每次通过循环都使用该 imageName 创建您的精灵。IE :

SKSpriteNode *sprite = [SKSpriteNode spriteNodeWithImageNamed:imageName];

在您的 SKTextureAtlas 测试中,显然使用相同的 imageName 来创建每个精灵。

现在...重新运行您的测试并记下每个测试中的平局计数。

这应该给你一个具体的例子,说明 SKTextureAtlas 的批处理渲染是什么。

这与渲染相同的精灵图像数千次无关。

这是关于在同一个绘制过程中绘制许多不同的精灵图像。

获得这种渲染优化可能会有一些开销,但我认为绘制计数应该是不言自明的,为什么在考虑所有因素时该开销是没有实际意义的。

现在,您可以假设更多:)

更新

正如评论中提到的,我的帖子是为了揭露为什么你的测试不是一个很好的测试 SKTextureAtlas 的好处,并且如果想以一种有意义的方式分析它是有缺陷的。你的测试就像用腮腺炎测试来测试麻疹。

下面是一个 github 项目,我将它放在一起以确定 SKTextureAtlas 适合并且确实优于 xcassets 的地方。

图集比较

只需在您的设备上运行该项目,然后点击以在测试之间切换。您可以知道它何时使用 SKTextureAtlas 进行测试,因为绘制计数为 1,帧速率为 60fps。

我隔离了将使用 SKTextureAtlas 优化的内容。这是一个 60 帧动画和 1600 个节点播放该动画。我偏移了它们的起始帧,这样它们就不会同时在同一个帧上。我还为这两个测试保持了统一,以便进行直接比较。

有人认为使用 SKTextureAtlas 只会优化所有渲染是不准确的。它的优化来自通过批量渲染减少绘制次数。因此,如果您的帧速率下降不是可以通过批量渲染来改善的,那么 SKTexture atlas 是不适合这项工作的工具。正确的 ?

类似于对象池,您可以通过不不断地创建和杀死游戏对象来获得优化,而是从对象池中重用它们。但是,如果您不是在游戏中不断地创建和杀死对象,那么池化不会优化您的游戏。

根据我在讨论日志中看到的您所描述的游戏问题,在您的情况下,池化可能是适合该工作的工具。

于 2014-08-11T05:35:56.717 回答