Search code examples
ioscolorssprite-kitskspritenodevector-graphics

Change node color in spritekit


I have a vector illustration of a branch with a few leaves on it. I am moving the branch from the bottom of the screen to the top of the screen. But as the branch moves from the initial position (screen bottom) to the final position (top of screen) I want the branches to change color from green to orange as they move to the top. It should be a smooth transition. I have the branch and leaves as vector images. I am using spritekit(ios) for development. The branch has been attached in the link below I do not want the color to instantly change from green to red. I want it to slowly transition from green to red as the branch moves to the top

https://ibb.co/bNH7P8


Solution

  • enter image description here

    Images

    You'll need 2 images, the green one

    enter image description here

    and the red one.

    enter image description here

    Element

    Now you need a node to hold both images

    class Element: SKNode {
    
        private let green = SKSpriteNode(imageNamed: "green")
        private let red = SKSpriteNode(imageNamed: "red")
    
        override init() {
            super.init()
            self.addChild(green)
            red.alpha = 0
            self.addChild(red)
        }
    
        required init?(coder aDecoder: NSCoder) {
            fatalError("init(coder:) has not been implemented")
        }
    
        func turnRed(duration: TimeInterval) {
            green.run(.fadeOut(withDuration: duration))
            red.run(.fadeIn(withDuration: duration))
        }
    
    }
    

    Animation

    Finally you just need to invoke the turnRed(duration:) method

    class GameScene: SKScene {
    
        let element = Element()
    
        override func didMove(to view: SKView) {
            self.addChild(element)
        }
    
        override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    
            // move the element to bottom
            let bottomY = self.frame.minY + element.calculateAccumulatedFrame().height / 2
            let moveToBottom = SKAction.moveTo(y: bottomY, duration: 2)
            element.run(moveToBottom)
    
            // change the color
            element.turnRed(duration: 2)
        }
    }
    

    Update

    If you want to set the color at a given ratio between green and red then use the following code

    class Element: SKNode {
    
        private let green = SKSpriteNode(imageNamed: "green")
        private let red = SKSpriteNode(imageNamed: "red")
    
        override init() {
            super.init()
            self.addChild(green)
            red.alpha = 0
            self.addChild(red)
        }
    
        required init?(coder aDecoder: NSCoder) {
            fatalError("init(coder:) has not been implemented")
        }
    
        // colorProgressionRatio must be a value between 1 (full green) and 0 (full red)
        func update(colorProgressionRatio: CGFloat) {
            guard colorProgressionRatio >= 0 && colorProgressionRatio <= 1 else {
                debugPrint("colorProgressionRatio must be a value between 0 and 1")
                return
            }
    
            let greenIntensity: CGFloat
            let redIntensity: CGFloat
    
            if colorProgressionRatio == 0 {
                greenIntensity = 0
                redIntensity = 1
            } else if colorProgressionRatio == 1 {
                greenIntensity = 1
                redIntensity = 0          
            } else {
                greenIntensity = colorProgressionRatio
                redIntensity = 1 - colorProgressionRatio
            }
    
            green.run(.fadeAlpha(to: greenIntensity, duration: 2))
            red.run(.fadeAlpha(to: redIntensity, duration: 2))
    
        }
    
    }
    

    Now you just need to call

    element.update(colorProgressionRatio: 0.4)
    

    passing a value between 0 and 1 (0 means red and 1 means full green).