Reputation: 611
I really wish to add a CIFilter to my SKScene. That I can do quite easily in fact by putting the following into my didMove(to view: SKView)
function of my GameScene
Class:
let grayscaleFilter = CIFilter(name: "CIColorControls", withInputParameters: ["inputBrightness" : 0.0, "inputContrast" : 1.1, "inputSaturation" : 0.0])!
grayscaleFilter.name = "grayscale"
self.filter = grayscaleFilter
self.shouldEnableEffects = true
Now my issue come with attempting to animate it, to my knowledge the only way to efficiently animate CIFilters is with Core Animation. I know that Core Animations can only be added to CALayer so I tried the following code in my didMove(to view: SKView)
function of my GameScene
Class:
let grayscaleFilter = CIFilter(name: "CIColorControls", withInputParameters: ["inputBrightness" : 0.0, "inputContrast" : 1.1, "inputSaturation" : 0.0])!
grayscaleFilter.name = "grayscale"
let grayscaleAnimation = CABasicAnimation(keyPath: "filters.grayscale.inputSaturation")
grayscaleAnimation.fromValue = 0.0
grayscaleAnimation.toValue = 1.0
grayscaleAnimation.duration = 5
view.isMultipleTouchEnabled = false
view.layer.filters?.append(grayscaleFilter)
view.layer.add(grayscaleAnimation, forKey: "grayscaleAnimation")
I get no results at all. No animations. No filter at all. Does anybody know a way to do this in a way that works, and could anyone explain why my current method doesn't work. Any help is appreciated, thanks in advance.
Upvotes: 1
Views: 421
Reputation: 2201
Here is a way I know of that works, using only SpriteKit (no Core Animation). First you create the filter, store it:
let filter = CIFilter(name: "CIExposureAdjust", withInputParameters: ["inputEV": 0])
self.filter = filter // store it
scene.filter = filter // so the whole scene will be filtered
scene.shouldEnableEffects = true
Then you create an SKAction that changes a property of the filter.
let duration = 1.0
let a = SKAction.customAction(withDuration: duration) { (node, elapsed) in
let percent = elapsed / CGFloat(duration)
// Animate inputEV from 0 to 2.5
self.filter.setValue(percent * 2.5, forKey: "inputEV")
}
a.timingMode = .easeIn
scene.run(a)
And if you don't want to filter the whole scene, you can use an SKEffectNode in the same way. But instead of assigning the filter to the scene, you assign it to the SKEffectNode. However, you need to add this line in the SKAction block, after updating the filter's properties:
self.myEffectNode.shouldEnableEffects = true
Without that line in the SKAction block, the animation won't work. I regard this as a bug. You don't have to do this if you're setting the filter on the whole scene though.
Upvotes: 2