Search code examples
sprite-kitskspritenodehsb

Get and change hue of SKSpriteNode's SKColor(HSBA)?


A SKSpriteNode's SKColor has a way to be created with Hue, Saturation, Brightness & Alpha:

    let myColor = SKColor(hue: 0.5, saturation: 1, brightness: 1, alpha: 1)
 mySprite.color = myColor

How do I get at the hue of a SKSpriteNode and make a change to it? eg, divide it by 2.


Solution

  • An SKSpriteNode is a node that draws a texture (optionally blended with a color), an image, a colored square. So, this is it's nature.

    When you make an SKSpriteNode, you have an instance property that represent the texture used to draw the sprite called also texture

    Since iOS 9.x, we are able to retrieve an image from a texture following the code below. In this example I call my SKSpriteNode as spriteBg:

    let spriteBg = SKSpriteNode.init(texture: SKTexture.init(imageNamed: "myImage.png"))
    
    if let txt = spriteBg.texture {
                if #available(iOS 9.0, *) {
                    let image : UIImage = UIImage.init(cgImage:txt.cgImage())
                } else {
                    // Fallback on earlier versions and forgot this code..
                }
    }
    

    Following this interesting answer, we can translate it to a more confortable Swift 3.0 version:

    func imageWith(source: UIImage, rotatedByHue: CGFloat) -> UIImage {
            // Create a Core Image version of the image.
            let sourceCore = CIImage(cgImage: source.cgImage!)
            // Apply a CIHueAdjust filter
            guard let hueAdjust = CIFilter(name: "CIHueAdjust") else { return source }
            hueAdjust.setDefaults()
            hueAdjust.setValue(sourceCore, forKey: "inputImage")
            hueAdjust.setValue(CGFloat(rotatedByHue), forKey: "inputAngle")
            let resultCore  = hueAdjust.value(forKey: "outputImage") as! CIImage!
            let context = CIContext(options: nil)
            let resultRef = context.createCGImage(resultCore!, from: resultCore!.extent)
            let result = UIImage(cgImage: resultRef!)
            return result
    }
    

    So, finally with the previous code we can do:

    if let txt = spriteBg.texture {
                if #available(iOS 9.0, *) {
                    let image : UIImage = UIImage.init(cgImage:txt.cgImage())
                    let changedImage = imageWith(source: image, rotatedByHue: 0.5)
                    spriteBg.texture = SKTexture(image: changedImage)
                } else {
                    // Fallback on earlier versions or bought a new iphone
                }
    }