我正在制作游戏,我注意到在某些场景中,我的FPS一直在55-60FPS区域附近(使用纹理图集)。这让我疯了,所以我决定把我所有的资产都放到Images.xcassets文件夹中,然后稳定60FPS。
我认为这是一个侥幸或我做错了什么,所以我决定开始一个新项目并执行一些基准......
测试(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对应方式更好。尽管如此,地图集确实比mcassets更好地管理内存。
有人知道为什么这些结果表明images.xcassets的性能比地图集好吗?
我提出了一些假设:
更新
对于下一个测试,我继续前进,并在它离开屏幕后从父级中删除了精灵。我还使用了7种不同的图像。我们应该看到由于抽奖计数而使用地图集的巨大性能提升但是......
答案 0 :(得分: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创建您的精灵。即:
SKSpriteNode *sprite = [SKSpriteNode spriteNodeWithImageNamed:imageName];
在您的SKTextureAtlas测试中,显然使用相同的imageName来创建每个精灵。
现在......重新运行测试并记下每次测试中的抽奖计数。
这应该为您提供有关SKTextureAtlas批处理渲染的实际示例。
没有关于渲染相同的精灵图像数千次。
关于在同一个绘图过程中绘制许多不同的精灵图像。
获得此渲染优化可能会有一些开销,但我认为绘制计数应该是自解释为什么在考虑所有事情时这种开销没有实际意义。
现在,你可以假设更多:)
<强>更新强>
正如评论中所提到的,我的帖子是揭露为什么你的测试不是SKTextureAtlas的好处的好测试,并且如果想要以有意义的方式分析它是有缺陷的。你的测试就像用麻痹试验测试麻疹一样。
下面是一个github项目,我将它放在一起,以确定SKTextureAtlas的适用位置,并且确实优于xcassets。
只需在您的设备上运行该项目,然后点击即可在测试之间切换。您可以告诉它何时使用SKTextureAtlas进行测试,因为绘制计数为1,帧速率为60fps。
我分离了将使用SKTextureAtlas进行优化的内容。它是一个60帧动画和1600个节点播放该动画。我偏移它们的起始帧,以便它们不会同时在同一帧上。我还为两个测试保持一致,所以它是直接比较。
有人认为使用SKTextureAtlas只会优化所有渲染,这是不准确的。它的优化来自于通过批量渲染减少抽取计数。因此,如果您的帧速率减慢不能通过批量渲染得到改善,那么SKTexture地图册就是错误的工具。对吗?
与对象池相似,您可以通过不经常创建和终止游戏对象来获得优化,而是从对象池中重用它们。但是,如果你不是经常在你的游戏中创建和杀死对象,那么就可以优化你的游戏。
根据我在讨论日志中描述的游戏问题,根据您的情况,汇集可能是正确的工具。