Sprite Kit的主要iOS9性能问题

Smi*_*key 12 performance objective-c sprite-kit ios9 xcode7

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

我的游戏已经从原来的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;
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

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

UPDATE

下面是同一场景的一些数字,以及游戏一次产生的绝对最大节点数.

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上,相同的项目,我可以在帧速率降至<30之前添加大约25个.

iPad2上的iOS 8:

在此输入图像描述

iOS 9 iPhone 5:

在此输入图像描述

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

更新3

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

Con*_*sed 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帧速率)中表达的理论是,它是iOS的一部分,旨在促进iPad Pro中可能使用的可变帧速率技术,并可能在其他设备中使用.

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

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

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

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

对于这两组问题所造成的问题,苹果的沉默和看似漠不关心的态度(很可能)非常强烈地表明他们对"他们的游戏开发社区"的看法.

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


Smi*_*key 7

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

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

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

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


Sky*_*ren 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
Run Code Online (Sandbox Code Playgroud)

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

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

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

2015-10-20 10:46:50.640 Test[2218:658384] <CAMetalLayer: 0x15fe987c0>: calling -display has no effect.
Run Code Online (Sandbox Code Playgroud)

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

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

看起来其他人正在为此归档错误......