在 SKScene、iOS、Swift 中获取/设置像素颜色

Posted

技术标签:

【中文标题】在 SKScene、iOS、Swift 中获取/设置像素颜色【英文标题】:Get/Set pixel color in SKScene, iOS, Swift 【发布时间】:2016-06-21 05:10:25 【问题描述】:

我正在尝试编写一个处理像素的 ios 游戏。我发现我可以使用here 提到的方法获取像素颜色,还有其他方法可以获取图像中像素的颜色。但我找不到任何关于在 SKScene 中获取像素颜色的信息。 As no answer for this question

我认为它与在 UIView 中使用的方法非常相似,但我不熟悉 Swift 中的像素编码。这是我在 UIView 中用于获取像素颜色的方法:

  func getPixelColorAtPoint(point:CGPoint) -> UIColor

    let pixel = UnsafeMutablePointer<CUnsignedChar>.alloc(4)
    let colorSpace = CGColorSpaceCreateDeviceRGB()
    let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.PremultipliedLast.rawValue)
    let context = CGBitmapContextCreate(pixel, 1, 1, 8, 4, colorSpace, bitmapInfo.rawValue)

    CGContextTranslateCTM(context, -point.x, -point.y)
    self.layer.renderInContext(context!)
    let color:UIColor = UIColor(red: CGFloat(pixel[0])/255.0, green: CGFloat(pixel[1])/255.0, blue: CGFloat(pixel[2])/255.0, alpha: CGFloat(pixel[3])/255.0)

    pixel.dealloc(4)
    return color
  

我想我需要更改'''self.layer....'''这一行。谁能帮我解决这个问题?

另外,我找不到任何关于如何直接在 UIView 或 SKScene 中设置像素颜色的信息。有什么想法吗?

顺便说一句:我尝试创建一个大小 = 1 像素的 UIView/SKNode 类,然后将其添加到 UIView/SKScene 以便我可以直接设置颜色。这对于少量像素是可行的。但我正在处理很多,可能有数百或数千个。这不是正确的方法,因为性能很差。

【问题讨论】:

你看过 SKMutableTexture modifyPixelDataWithBlock 吗?显然您可以修改纹理上的像素数据。如果你有一个带有纹理的 SKSpriteNode,你应该能够按像素修改它。例如,为了获取像素颜色值,您似乎需要使用 UIView。 @GOR 我从来没有使用过 modifyPixelDataWithBlock,你能提供一些答案来说明如何使用吗? @GOR 听起来可行。我阅读了文档,它说除非我别无选择,否则我最好不要这样做,因为性能原因。我不确定它如何处理许多像素并经常更新。但是,你能告诉我一些教程链接的代码吗?谢谢 没用过。这会有帮助吗? ***.com/questions/28398677/… 【参考方案1】:

最近我尝试使用此扩展程序从 SKTexture 获取像素,这对我有用:

extension SKTexture 
    func getPixelColorFromTexture(position: CGPoint) -> SKColor 
        let view = SKView(frame: CGRectMake(0, 0, 1, 1))
        let scene = SKScene(size: CGSize(width: 1, height: 1))
        let sprite  = SKSpriteNode(texture: self)
        sprite.anchorPoint = CGPointZero
        sprite.position = CGPoint(x: -floor(position.x), y: -floor(position.y))
        scene.anchorPoint = CGPointZero
        scene.addChild(sprite)
        view.presentScene(scene)
        var pixel: [UInt8] = [0, 0, 0, 0]
        let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.PremultipliedLast.rawValue).rawValue
        let context = CGBitmapContextCreate(&pixel, 1, 1, 8, 4, CGColorSpaceCreateDeviceRGB(), bitmapInfo)
        UIGraphicsPushContext(context!)
        view.drawViewHierarchyInRect(view.bounds, afterScreenUpdates: true)
        UIGraphicsPopContext()
        return SKColor(red: CGFloat(pixel[0]) / 255.0, green: CGFloat(pixel[1]) / 255.0, blue: CGFloat(pixel[2]) / 255.0, alpha: CGFloat(pixel[3]) / 255.0)
    

【讨论】:

我看了你的回答。我相信它有效,但我有几个担忧。 (1):每读取一个像素,就创建一个新的SKView,一个新的SKScene,一个新的Sprite。由于我要为每个更新帧(60FPS)处理许多像素,我可以想象这会导致性能不佳。正如我在帖子中提到的,我尝试为每个像素创建一个 UIView,然后获取颜色并更改颜色,并更新每个帧。 (2):我现在并没有真正处理 SKTexture。我所拥有的只是一个纯色背景和一些纯色精灵。我想我可以将它们转换为纹理,但我想知道是否可以先直接处理 Core Graphics。 我的方法遵循 UIKit 中的 Sprite-kit 实现,所以我们需要呈现场景以使用 CGBitmapContextCreate(宽度和高度等于 1)。我试过了,它似乎不打扰帧率。如果您尝试另一种方式并且它有效,请发布它,可以帮助所有人。我喜欢你的问题,它会被投票或加注,这很有趣。 取色方式对fps影响不大。我关心的是设置颜色步长。我正在寻找一种更基本的方法,例如:(1)计算所有需要更改的像素,(2)在单帧更新方法中刷新所有颜色。我尝试在 UIView 中执行此操作,但每次更改像素颜色时,框架都会自动刷新。所以性能真的很差。我相信像 CoreGraphics 这样的较低级别的实现会处理这项工作,但我对此并不熟悉。我会想办法,如果可能的话在这里发布答案。 很高兴你也觉得这很有趣。这个问题的灵感来自一些类似沙子的游戏。你可以在这里找到我之前问过的一个问题。 here。从那里的答案看来,这似乎可以很容易地为 JS 完成。我一直在为 Swift 寻找类似的实现。如果您将来找到任何好的解决方案,请告诉我。

以上是关于在 SKScene、iOS、Swift 中获取/设置像素颜色的主要内容,如果未能解决你的问题,请参考以下文章

如何将 swift 文件与 SKscene 连接?

如何在 Swift Playgrounds 中使用带有纹理的 SKNode 设置 SKScene?

如何使用 Swift 正确切换 SpriteKit 中的 SKScene?

如何在 Swift 中将 SKScene 覆盖在 SCNScene 上?

从 UIViewController 呈现 SKScene - Swift

Swift SKScene 在 Objective-C 项目中显示为空白