在OS X上全屏模式下的Sprite Kit严重FPS问题

Epi*_*yte 9 macos frame-rate sprite-kit

我正在制作一个相当复杂的精灵套装游戏.我最近添加了对OS X的支持.我总是得到60 fps,无论在调整窗口大小时我的游戏是如何缩放的(即使调整大小到最大屏幕空间).但是,当我让我的应用程序进入"全屏"时,fps下降到30-40 fps并保持这种状态?但是,如果我在启用全屏时使用鼠标光标并显示菜单栏,则fps会恢复到60 fps!

你甚至可以使用默认模板在Xcode中为mac制作一个sprite kit游戏来测试这个bug.这是我拍摄的Mac默认游戏模板的屏幕截图.

我建议您自己尝试一下,如果您使用Apple的OS X默认精灵工具包模板,您甚至不必编写任何代码.

最大窗口(无FPS问题:59-60 FPS) 在此输入图像描述

全屏模式(FPS降至30-40 FPS) 在此输入图像描述

全屏模式鼠标在顶部显示菜单栏(令人惊讶的是,没有FPS问题:59-60 FPS) 在此输入图像描述

任何人都知道可能导致这个问题的原因.如果这意味着用户将失去性能,我不想以全屏模式发布我的应用程序.你会认为全屏模式可以更好地优化绘图,但显然它恰恰相反.我在优胜美地上跑步.

Epi*_*yte 9

好的,经过几周的调查,我找到了一些解决这个问题的方法.在开始之前,让我先解释一下我的设置.我在一个包含SKView的故事板中使用NSViewController.我已经在MacBook Pro(Retina,15英寸,2013年初)上测试了解决方法,我不知道下面的解决方法是否适用于其他Mac.我相信应该,当我有机会时,我会测试并查看下面的解决方法是否有效.

所以在开始之前,让我们回顾一下问题所在.问题是通过单击全屏按钮使您的应用程序进入全屏导致FPS大幅下降.以下是启用全屏按钮的方法:

self.view.window!.collectionBehavior = .FullScreenPrimary
Run Code Online (Sandbox Code Playgroud)

然后我四处搜索,发现使用此代码进入全屏的不同方式:

 self.view.enterFullScreenMode(NSScreen.mainScreen()!, withOptions: nil)
Run Code Online (Sandbox Code Playgroud)

但我的FPS仍然大幅下降.请记住,在最大化窗口模式或甚至全屏显示菜单栏时,我没有fps问题!(见有问题的图片).

那么我尝试了一种不太高级的方法来全屏显示.我在这里找到了Apple的指南

使用指南中的一些代码,我设法通过将窗口大小设置为显示大小来进入全屏,并将窗口定位在所有OS X UI之上.代码如下:

self.view.window!.styleMask = NSBorderlessWindowMask
self.view.window!.level = Int(CGWindowLevelForKey(Int32(kCGMainMenuWindowLevelKey))) + 1
self.view.window!.opaque = true
self.view.window!.hidesOnDeactivate = true
let size = NSScreen.mainScreen()!.frame.size
self.view.window!.setFrame(CGRect(x: 0, y: 0, width: size.width, height: size.height), display:true)
Run Code Online (Sandbox Code Playgroud)

但是,遗憾的是,同样的问题...... FPS就像以前一样掉了下来.

那么我想如果我弄乱了窗户的大小/位置会怎样.所以我尝试向下移动窗口,以便只显示菜单栏,如下所示.而且这个工作.我的fps不再下降了.但显然它不是真正的全屏,因为菜单栏是可见的

self.view.window!.setFrame(CGRect(x: 0, y: 0, width: size.width, height: size.height-NSApplication.sharedApplication().mainMenu!.menuBarHeight), display:true)
Run Code Online (Sandbox Code Playgroud)

事实上,事实证明,只需将窗口大小调整1点即可修复fps的下降.因此,当窗口大小与屏幕大小匹配时,bug必须与苹果的优化(多么具有讽刺意味)有关.

不相信我?以下是该链接的引用.

OS X v10.6及更高版本自动优化屏幕大小的窗口的性能

因此,为了解决这个问题,我们需要做的就是使窗口大小高1点,这将阻止OS X尝试优化窗口.这将导致您的应用程序在顶部稍微切断,但1像素根本不应该是明显的.在最坏的情况下,您可以将节点位置调整1个点来解决这个问题.


为方便起见,下面列出了2个解决方法.这两种解决方法都不会导致FPS下降.您的应用程序应该像在最大化窗口模式中一样运行.第一个解决方法是将您的应用程序全屏显示,并在顶部显示菜单栏.第二种解决方法是将您的应用程序完全全屏显示,没有菜单栏.

解决方法1:使用菜单栏全屏

self.view.window!.styleMask = NSBorderlessWindowMask
self.view.window!.level = Int(CGWindowLevelForKey(Int32(kCGMainMenuWindowLevelKey))) + 1
self.view.window!.opaque = true
self.view.window!.hidesOnDeactivate = true

let size = NSScreen.mainScreen()!.frame.size
self.view.window!.setFrame(CGRect(x: 0, y: 0, width: size.width, height: size.height-NSApplication.sharedApplication().mainMenu!.menuBarHeight), display:true)
Run Code Online (Sandbox Code Playgroud)

解决方法2:全屏但没有菜单栏

self.view.window!.styleMask = NSBorderlessWindowMask
self.view.window!.level = Int(CGWindowLevelForKey(Int32(kCGMainMenuWindowLevelKey))) + 1
self.view.window!.opaque = true
self.view.window!.hidesOnDeactivate = true
let size = NSScreen.mainScreen()!.frame.size
NSMenu.setMenuBarVisible(false)
self.view.window!.setFrame(CGRect(x: 0, y: 0, width: size.width, height: size.height+1), display:true)
Run Code Online (Sandbox Code Playgroud)

如果由于某种原因这些变通方法不起作用,请尝试使用窗口的大小/位置进行更多操作.此外,您可能需要更改窗口级别,具体取决于您是否有其他视图,例如您的应用程序不应重叠的对话框.另请记得向Apple提交错误报告.


关于NSBorderlessWindowMask的其他信息

这些变通方法使用NSBorderlessWindowMask.当键窗口改变时,这些类型的窗口不接受键盘输入.因此,如果您的游戏使用键盘输入,您应该覆盖以下内容.看到这里

 class CustomWindow: NSWindow {
    override var canBecomeKeyWindow: Bool {
        get {
            return true
        }
    }
    override var canBecomeMainWindow: Bool {
        get {
            return true
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

更新:一些坏消息

在Mac Book Air上测试了这种解决方法,除非减去大约100个点(显然非常明显),否则它不起作用.我不知道为什么.同样适用于andyvn22的解决方案.我也注意到很少,也许每60次发布一次,所提供的解决方法根本就不适用于Mac Book Air.唯一的解决方法是重新启动应用程序.也许Max Book Air是一个特例.也许缺少显卡与问题有关.希望Apple能够解决问题.我现在在支持全屏和不支持全屏之间挣扎.我真的希望用户能够进入全屏模式,但同时我不想让用户失去一半的FPS风险.