2

I'm trying to write a iOS game dealing with pixels. I found that I can get pixel color with method mentioned here, and there other method for getting color of pixel in images too. But I could not find any information on getting color of pixel in SKScene. As no answer for this question

I image it would be very similar to the method used to do it in UIView, but I'm not familiar with pixel coding in Swift. Here is what I used for getting pixel color in 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
  }

I guess I need to change the line '''self.layer....'''. Could anyone help me with this?

Also, I could not find any information about how to set a pixel color directly in UIView or SKScene. Any ideas?

BTW: I tried to create a UIView/SKNode class with size = 1 pixel, then add it to the UIView/SKScene so I can set the color directly. This is doable for small amount of pixels. But I'm dealing with lots of them, probably hundreds or thousands. This is not the right way to do it since the performance is very poor.

Community
  • 1
  • 1
Valar Morghulis
  • 647
  • 5
  • 16
  • 1
    Did you take a look at SKMutableTexture modifyPixelDataWithBlock? Apparently you can modify pixel data on the texture. If you then have a SKSpriteNode with the texture you should be able to modify it per-pixel. For getting the pixel color values it seems you need to use the UIView for example. – OwlOCR Jun 21 '16 at 06:55
  • @GOR I dont have never use modifyPixelDataWithBlock, can you provide some answer to show how? – Alessandro Ornano Jun 21 '16 at 17:00
  • @GOR Sounds doable. I read the document, it says I'd better not do this due to performance unless I have no choice. I'm not sure how it performs with many pixels and update frequently. However, can you show me some codes for some links of tutorials? thanks – Valar Morghulis Jun 21 '16 at 17:32
  • Haven't used it. Would this help? http://stackoverflow.com/questions/28398677/what-is-unsafemutablepointervoid-how-to-modify-the-underlying-memory – OwlOCR Jun 22 '16 at 06:41

1 Answers1

0

Recently I try this extension to get pixel from a SKTexture and this work for me:

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)
    }
}
Alessandro Ornano
  • 34,887
  • 11
  • 106
  • 133
  • 1
    I went through your answer. I believe it works, but I have several concerns. (1): Everytime it reads one pixel, it create a new SKView, a new SKScene, a new Sprite. Since I'm dealing with many pixels for every update frame (60FPS), I can image this would give a bad performance. As I mentioned in my post, I tried to create a UIView for each pixel then get the color and change the color, and update each frame too. – Valar Morghulis Jun 21 '16 at 17:30
  • (2): I'm not really dealing with SKTexture at this moment. All I have is a pure color background with some pure color sprite. I guess I can convert those to texture but I want to know if I could directly deal with Core Graphics first. – Valar Morghulis Jun 21 '16 at 17:30
  • My method follow the Sprite-kit implementation in UIKit so we need to present the scene to work with CGBitmapContextCreate (width and height is equal to 1).I've tried and it seems don't disturb the fps. If you try another way and it works please post it, can be help all. I like your question, it would be voted or bounted, it's very interesting. – Alessandro Ornano Jun 21 '16 at 17:38
  • The getting color method would not affect fps much. my concern is for setting color step. I'm looking for a more fundamental method, like: (1) calculate all pixels need to change, (2) refresh all color in single frame update method. I've tried doing this in UIView, but everytime I change the pixels colors, the frame would automatically refresh. So the performance is really bad. I believe a lower level implementation like CoreGraphics would handle the job, but I'm not familiar with that. I'll find a way, and post an answer here if possible. – Valar Morghulis Jun 21 '16 at 18:36
  • I'm glad you think it's interesting too. This question is inspired by some sand-like games. You can find one question here I asked before. [here](http://stackoverflow.com/questions/37893912/physics-engine-for-games-like-sugar-sugar-spritekit-performance-optimization/37897196?noredirect=1#comment63259354_37897196). From the answer there, It seems this can be done for JS very easily. I was looking for a similar implementation for Swift. Tell me if you find any good solution in the future. – Valar Morghulis Jun 21 '16 at 18:39
  • Yes, good observations.Im here because honestly SKShapeNode is a piece of crap! Too many shapes to make a simple dynamic objects waste my fps performance so change pixel colors seems the only way to do. I was thinking about an extension that have an array of pixels as input (so 1 pixel or n pixels). I will try to study a method, hope someone have a great solution, I will post my experiments here. – Alessandro Ornano Jun 21 '16 at 18:43
  • HAHA, can't agree with you anymore about the SHITTY SKShapeNode. I read a lot of articles talking about how shitty ShapeNode is before I made any games. I paid no attention, until I use some in my game. It really destroy the performance since it would re-draw itself EVERY frame! So the workaround for me, is to create a shapeNode, then save it as a sktexture, then use it to create a SKSpriteNode, and that works like a charm. Maybe you can try that if not dealing with pixels. But with pixel, I need to find another method. – Valar Morghulis Jun 21 '16 at 18:58
  • BTW, I found lots of articles about how to get/set the pixel for UIImage, since there are apps dealing with filter/photo editing etc. But no articles on how to directly change a pixel in a UIView or SKScene, I would image it should be possible using the same techniques in UIImage. I would look it in that direction. – Valar Morghulis Jun 21 '16 at 19:02
  • Yes, there arent Sprite-kit articles about pixels both for objective-c or swift. When you re-create ShapeNode you subclassing SKNode? Actually Im fight with these dynamic lines composed by SKShapeNode stupid connected points removed and re-created always for a more big lnes by cgpath – Alessandro Ornano Jun 21 '16 at 19:05
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/115230/discussion-between-alessandro-ornano-and-valar-morghulis). – Alessandro Ornano Jun 21 '16 at 19:08