【问题标题】:ios Sprite Kit screengrab?ios Sprite Kit 截图?
【发布时间】: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 帧缓冲区。示例:stackoverflow.com/questions/11769006/… 问题是 glReadPixels 是否会返回任何有意义的内容,因为尽管您可以通过 [EAGLContext currentContext] 获取 GL 上下文,但 SKView 的 open gl 并未公开。

标签: ios objective-c swift sprite-kit uigraphicscontext


【解决方案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..
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-10-15
        • 2013-11-19
        • 1970-01-01
        • 2014-04-19
        • 1970-01-01
        • 1970-01-01
        • 2013-12-14
        • 1970-01-01
        相关资源
        最近更新 更多