ios Sprite Kit 截图?

Posted

技术标签:

【中文标题】ios Sprite Kit 截图?【英文标题】:ios Sprite Kit screengrab? 【发布时间】:2013-11-03 11:32:09 【问题描述】:

我正在尝试获取其中包含 SKScene 的视图的屏幕截图。我使用的技术是:

UIGraphicsBeginImageContextWithOptions(self.view.bounds.size, NO, scale);
[self.view.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *viewImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

这适用于普通 UIView,但无论出于何种原因,它都会忽略 SKScene 中的所有精灵。

我不确定这是否是一个错误,或者 Sprite Kit 的渲染是否与 UIGraphics 分开。

问题:当 UIViews 的工作方式似乎不适用于 Sprite Kit 时,我如何获取 SKScene 的屏幕抓图,或者是否有人成功使用带有 Sprite Kit 的 UIGraphics 上下文?

【问题讨论】:

好问题。由于 SKView 使用的是 OpenGL,因此您需要使用代码来获取 OpenGL 帧缓冲区。示例:***.com/questions/11769006/… 问题是 glReadPixels 是否会返回任何有意义的内容,因为尽管您可以通过 [EAGLContext currentContext] 获取 GL 上下文,但 SKView 的 open gl 并未公开。 见***.com/a/37625473/763355 【参考方案1】:

您几乎拥有它,但问题如上面评论中所述。如果您想捕获SKScene 的内容,请尝试以下操作:

UIGraphicsBeginImageContextWithOptions(self.view.bounds.size, NO, scale);
[self.view drawViewHierarchyInRect:self.bounds afterScreenUpdates:YES];
UIImage *viewImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

解决方法基本上是改用新方法drawViewHierarchyInRect:afterScreenUpdates,这是我们目前最好的;请注意,它并不是很快,因此实时执行此操作并不美观。

【讨论】:

@Matt 说通过这种方法抓取一个屏幕需要多快? “不完全快速”大致相当于什么? 在我的简单测试场景中不到 500 毫秒,但如果不对您的特定场景进行基准测试就很难说。更少的精灵/动作似乎使它更快一点。如果这是一个偶然的功能,它不是一个主要问题。但是如果你想做实时处理(即模拟移动精灵的模糊效果),我怀疑这在当前的硬件上是否有效。 两种屏幕抓取方法对于移动精灵来说都太慢了。那是我以前尝试过的。现在,我只是偶尔为出现在屏幕上的视图做一次(有点像 UIAlertView)。当不处于紧密循环中时,两种屏幕抓取方法运行速度都足够快,不会被注意到。 我发现即使您对 afterScreenUpdates 说“是”,也不会应用挂起的更改(例如隐藏节点)。 (ios8.3,iPhone 4s)。屏幕截图仍然是以前的状态。但是,像这样调用屏幕抓取确实解决了它:[self runAction:[SKAction waitForDuration:0.0001] completion:^ dothescreengrab ];【参考方案2】:

作为一种更快的替代方法,您可以在SKView 上使用textureFromNode 方法,该方法将视图图像作为SKTexture 返回。只需将 SKScene 作为参数传递:

let texture = skView.textureFromNode(scene)

或捕捉部分场景:

let texture = skView.textureFromNode(scene, crop: cropRect)

【讨论】:

【参考方案3】:

//1:从“someNode”获取纹理

let texture = skView.textureFromNode(someNode)

//2:从节点纹理中获取UIImage

let image = UIImage(cgImage: texture!.cgImage())

【讨论】:

【参考方案4】:

Swift 的解决方案:

func getScreenshot(scene: SKScene, duration:TimeInterval = 0.0001, completion:((_ txt:SKTexture) -> Void)?) 
    let action = SKAction.run 
        let bounds = scene.view?.bounds
        var image = UIImage()
        UIGraphicsBeginImageContextWithOptions(bounds!.size, true, UIScreen.main.scale)
        scene.view?.drawHierarchy(in: bounds!, afterScreenUpdates: true)
        if let screenshot = UIGraphicsGetImageFromCurrentImageContext() 
            UIGraphicsEndImageContext()
            image = screenshot
         else 
            assertionFailure("Unable to make a screenshot for the scene \(type(of:scene))")
        
        completion!(SKTexture(image: image))
    
    let wait = SKAction.wait(forDuration: duration)
    let seq = SKAction.sequence([wait,action])
    scene.run(seq,withKey:"getScreenshot")

用法

getScreenshot(scene: self, completion: (txt) -> Void in
            let thumbNode = SKSpriteNode(texture: txt, size:CGSize(width:300,height:224))
            // do whatever you want with your screenshot..

【讨论】:

以上是关于ios Sprite Kit 截图?的主要内容,如果未能解决你的问题,请参考以下文章

Sprite Kit 动画:Atlas 错误

iOS 7 Sprite Kit 动画速度变化

Sprite Kit,删除 Sprite 以进行碰撞

使用 Touch iOS Sprite Kit 画线

iOS 7 Sprite Kit 释放内存

Physics Body 边缘 IOS8,Sprite Kit