Sprite Kit

时间:2015-10-09 16:44:03

标签: objective-c performance sprite-kit ios9 xcode7

我遇到了iOS9的巨大性能问题,我无法弄清楚该怎么做。我已经阅读了很多帖子 - 例如herehere,但他们建议的解决方案并没有帮助,也没什么区别。

我的游戏从旧版iPad 2(iOS 8.4)上的60fps变为<在新的iPad mini(iOS 9)上15fps。

我试图解决主要罪魁祸首。我很确定其中一个是SKCropNodes。我通常在场景中渲染几个SKCropNodes(6-18)。这在iOS8中从来都不是问题,但它看起来像是iOS9,虽然它可以更好地裁剪,但也会降低性能。

如果我将裁剪节点渲染为普通的SKSpriteNodes,我可以在旧设备上获得5fps,在较新的iPhone 6上获得高达30fps。我无法使用裁剪节点,但它无法成为整体问题。

我想也许正在使用错误的纹理图集 - 即一个更大的分辨率。但是迫使我的设备使用非常小的地图集没有区别。

我使用Texture Packer为不同的设备生成具有缩放变体的地图集。我注意到XCAssets现在提供了添加Sprite Atlas的选项(我似乎无法找到任何关于此的文档)。这不适合我的游戏,因为我使用了100多个精灵。我尝试将我的地图集添加到XCAssets,但由于某种原因,它不会使用缩放变体。然而,由于纹理低,它仍然可以运行得非常糟糕。

我尝试过设置

skView.ignoresSiblingOrder = YES;

并给出了我所有节点的zPosition值,但仍然没有效果。我还为每个图像名称添加了.png扩展名(原来这个问题意味着他们不会渲染。)

我的场景中有一些SKEffectNodes,但删除和添加它们似乎没有效果。

我不明白相同的硬件和相同的代码如何产生如此截然不同的结果。显然,苹果已经改变了与渲染产生负面影响的事情。他们似乎也无意解决这些问题。我知道这个问题的漏洞已存在数月 - 早在iOS9发布之前。

我已经在这个游戏上工作了2年,而且只是在iOS9之前发布了它。它现在遭受了糟糕的表现和经常性的崩溃。

有没有人弄清楚Apple究竟做了什么来扼杀表现?如果我知道,我至少可以尝试解决它...谢谢。

更新

以下是同一场景的一些数字,其中游戏一次会产生绝对最大数量的节点。

iOS 8,iPad 2,〜200个节点,~100个绘图,58.7 - 60 fps

iOS 9,iPhone6,~280个节点,~216个绘图,大约20 fps

我认为节点数量的差异是由于屏幕尺寸不同造成的。如果我改变iPhone 6上的场景以达到相同的值,则FPS仍然在24左右。

更新2

使用Xcode的模板Sprite Kit项目,并将太空船更改为包含太空船的SKCropNode,在iOS 8上,我可以添加100个没有帧率问题的船只。在iOS 9上,相同的项目,我可以在帧速率下降到<之前添加大约25个。 30.

iPad2上的iOS 8:

enter image description here

iOS 9 iPhone 5:

enter image description here

就纹理图集的使​​用而言,如我的评论中所述,我无法保证任何内容都来自相同的地图集。我的游戏包含自定义角色,其中包含来自各种地图集的资源(每个地图包含约100个纹理)。屏幕上一次最多可以有9个字符。我知道这在抽奖方面并不是最有效的,但在iOS9之前我一直没有问题...

更新3

我向Apple提交了一个错误,包括我的示例程序。我还用完了我的一项技术支持请求。到目前为止,Apple没有任何内容。

5 个答案:

答案 0 :(得分:13)

有两个主要问题。

一个是Sprite Kit从iOS 8到iOS 9的性能急剧下降,原因有很多,其中一些原因与你有关,但还有其他原因。似乎渲染,排序和存储/处理节点的许多方面要么被破坏,要么在CPU / GPU上加倍或增加三倍。

然而,另一个问题是进一步加强解决任何可能的性能问题的努力。它是一种普遍的,看似随意的帧速率上限机制,当它以40fps运行时最常见。但它也可以在其他频率上运行。

多年来,当人们手动使用CADisplayLink在每帧的帧上创建游戏循环或其他基于时序的机制时,这种上限(很少)被注意到。

借助iOS 9,这种看似自动化的封顶已经成为一种非常不受欢迎的功能"基于Sprite Kit,SceneKit,Metal和OpenGL ES的应用程序。

在SceneKit的情况下,这是最有说服力的,因为无论渲染选择 - 金属或OpenGL - 以及所有设备(包括新的6S手机和iPad Air 2等)都会出现封顶,即使是非常简单的默认设置模板项目。

"呈现器"是设备上屏幕上SceneKit的详细统计信息中的行项目。它是封盖过程中最明显的指示。当游戏以60fps的速度稳定运行时,它就不存在了。

当以40fps为上限时,无论在屏幕和逻辑上执行其他活动所需的时间量,此组件都将吸收游戏循环中所需的所有剩余时间,以保持稳定的40fps上限。它根据其他活动所需的时间而变化,总是强制底层操作系统的明显目标是将帧速率保持在40fps。

此问题与iOS 9 Sprite Kit性能相关的问题意味着目前可能无法解决您的所有问题。很难确定你何时击中其中一个(看似)任意的fps上限,而不是造成实际问题。

除此之外,这些上限不限于40fps。我以30fps,24fps,20fps,15fps,12fps和8fps注意到它们。

当然,Apple从未承认也没有承认操作系统中的这种封顶机制,也没有对何时/如何/为何如此影响游戏和渲染过程发表评论。

我在这篇文章(Inconsistent SceneKit framerate)中表达的理论是,它是iOS的一部分,旨在促进iPad Pro即将推出的可变帧速率技术的使用,并且可能在其他设备。

120Hz成为未来设备的基本速率是有道理的,特别是考虑到iOS的性能优势,新的Apple TV以及iPad Pro中的屏幕触摸/笔的240Hz采样......以及相当可观的市场上120Hz电视的数量。

即使没有可变的帧速率技术(比如......你的电视),120Hz的显示速率意味着24fps的电影可以以稳定的5:5:5帧显示模式播放 - 这大大增加了喜悦/沉浸时观看电影,几乎所有拍摄的电影都真正利用真正的24fps的优势来模糊和动作效果。

与目前在所有设备上使用的下拉方法相比,采用可变帧速率技术或5:5:5帧显示的120Hz也将节省Apple在胶片压缩和解压缩方面的巨大努力,最大帧速率为60fps

所有猜测,但我猜测在游戏引擎技术中使用这些帧速率限制是否有助于使游戏使用更少的功能,并且(在将来)开发人员可以选择框架锁定他们的可变帧率设备世界中的游戏。非常不幸的是(如果是这种情况)他们做了如此糟糕的工作或整理了操作系统中的封顶问题和Sprite Kit的性质,导致你盲目地战斗的场景获得良好,高效,一致的帧率。

对于这两组问题造成的问题,苹果公司的沉默和看似漠不关心的态度(很可能)非常强烈地表明了他们对游戏开发社区的感受#34;

这是处理封闭源框架中游戏制作所固有的尖端和性能关键发展问题的最大单一问题,这些问题来自于一个不必要的秘密和非交流(几乎是好战的)组织。

答案 1 :(得分:7)

似乎大多数iOS9问题都是在最新的iOS9.2测试版中解决的。 Xcode 7.2 beta。

感谢Apple的终于解决了这个问题。太糟糕了,我花了两个月的时间来处理解决方案。

我一直在Apple的论坛上发帖,提交错误并与支持技术人员沟通。令人遗憾的是,苹果公司在任何时候都不清楚他们所知道的问题,以及Sprite Kit团队正在解决的问题。

尽管如此,至少大部分Sprite Kit问题现在已经解决,并且不再需要改变职业:]

答案 2 :(得分:5)

在您提供的示例中,我可以看到一种方法来改善绘制计数并验证裁剪节点不是问题。我不知道这在你的实际游戏中有多实用,但是这极大地限制了你的抽签。

#import "GameScene.h"

@interface GameScene ()

@property(nonatomic, strong)SKTexture *spaceshipTexture;
@end

@implementation GameScene

-(void)didMoveToView:(SKView *)view {
    /* Setup your scene here */
    SKLabelNode *myLabel = [SKLabelNode labelNodeWithFontNamed:@"Chalkduster"];

    myLabel.text = @"Hello, World!";
    myLabel.fontSize = 45;
    myLabel.position = CGPointMake(CGRectGetMidX(self.frame),
                                   CGRectGetMidY(self.frame));

    [self addChild:myLabel];

    //Create one texture to be used over an over
    SKSpriteNode *sprite = [SKSpriteNode spriteNodeWithImageNamed:@"Spaceship"];
    sprite.xScale = 0.5;
    sprite.yScale = 0.5;

    SKCropNode *cropNode = [[SKCropNode alloc] init];
    SKSpriteNode *mask = [SKSpriteNode spriteNodeWithColor:[UIColor blackColor] size:CGSizeMake(100, 100)];
    mask.position = sprite.position;
    [cropNode setMaskNode:mask];
    [cropNode addChild:sprite];
    [self addChild:cropNode];

    //temp add to scene to create the texture than remove
    //keep pointer to texture so it can be reused
    self.spaceshipTexture = [self.view textureFromNode:cropNode];
    [cropNode removeFromParent];

}

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    /* Called when a touch begins */

    for (UITouch *touch in touches) {
        CGPoint location = [touch locationInNode:self];

        //re use texture
        SKSpriteNode *sprite = [SKSpriteNode spriteNodeWithTexture:self.spaceshipTexture];
        sprite.position = location;
        [self addChild:sprite];
    }
}

@end

缺点是当你在屏幕上获得120多个节点时问题仍然存在。

另请注意,我使用默认模板创建了一个新的SpriteKit应用程序并删除了SKAction。不幸的是,当你获得120多个节点时,即使默认的Apple模板也会遭受巨大的fps下降。所以我不知道是否会有答案,你最好的做法是提交错误报告,因为我相信它应该(并且能够)在屏幕上处理那么多,而不会丢失fps。

另外值得注意的是这个错误出现在默认项目上,可能是相关的......

2015-10-20 10:46:50.640 Test[2218:658384] <CAMetalLayer: 0x15fe987c0>: calling -display has no effect.

<强>更新 做了一点研究我遇到了这个......

https://forums.developer.apple.com/thread/14487

看起来其他人正在为此提出错误......

答案 3 :(得分:1)

很多抽奖......你试过这个吗?

skView.ignoresSiblingOrder = YES;

答案 4 :(得分:0)

您使用的是SKLightNode吗?如果是这样,请尝试从代码中删除所有光节点。我做到了这一点,我的游戏以60fps的速度运行,就像在iOS8中一样。

来源:SKLightNode performance issues