I have a SKSpriteNode which I fade out with baseNode.runAction(SKAction.fadeOutWithDuration(0.5))
The sprite has one Child. Also a SKSpriteNode. (The red block in the image)
While the baseNode fades out there is the contour of die child node.
What is the best way to avoid this and fade out the whole node with its children simultaneously? I want to play a Texture Animation in the child Node. So flatten is no solution.
You can use a parent SKEffectNode that wraps both the base node and the child node and do the fade on the effect node itself.
Even if you aren't using filters or other features of SKEffectNode, it renders its children in a private framebuffer, so it ends up doing what the flatten suggestion was trying to do, but it will take care of everything for you, even if the children are animating every frame, like you are going for in your example.
For performance, you can also disable the extra cost of using a parent SKEffectNode by setting shouldEnableEffects = false, and only turn this on/off when needing to do the fade.
This question raised my curiosity. I have a solution, but, for lack of my knowledge of Swift, have written it in Objective-C. It is very simple, however, and porting should be of no problem to you.
The trick is to flatten the entire node into a single texture and fade that instead.
I have implemented this using a Category. The code below replaces the texture
property of an SKSpriteNode with a flattened texture. The key method is -textureFromNode: inside the SKView
class.
@interface SKSpriteNode (Fading)
- (void)flattenForFading;
@end
...
#import "SKSpriteNode+Fading.h"
@implementation SKSpriteNode (Fading)
- (void)flattenForFading {
SKTexture *flattenedContents = [self.scene.view textureFromNode:self];
/// Copy the children array, so when we are iterating the removing doesn't cause any problems
NSArray *children = [self.children copy];
for (SKNode *child in children) {
[child removeFromParent];
}
self.texture = flattenedContents;
self.size = self.texture.size;
}
@end
In the case of a non-SKSpriteNode case you can just add a new SKSpriteNode as a child of the node being flattened. Animation inside the node is not supported since you're baking a single texture. Instead of removing all children, you could just hide them as well of course. If you would add an extra property for the removed texture, you could even save the internal state and revert this method's effect with a -unflatten
method. But that goes beyond the scope of your question.
I took this screenshot in the Simulator. Note that the node counter corresponds with the 3 faded SKSpriteNodes, 1 SKLabelNode and 1 flattened sprite (SKSpriteNode).
You will have to call the same action on the node's children as well.
baseNode.runAction(SKAction.fadeOutWithDuration(0.5))
for node in baseNode.children as! [SKSpriteNode]
{
node.runAction(SKAction.fadeOutWithDuration(0.5))
}
for transitions between screens a cool effect is to have a black node covering the entire screen, and then fading it out. I came up with the following: Swift 3
import SpriteKit
override func didEnter(from previousState: GKState?) {
let blackNode = SKSpriteNode(color: SKColor.black, size: scene.size)
blackNode.position = CGPoint(x: scene.size.width / 2, y: scene.size.height / 2)
blackNode.zPosition = Layer.top.rawValue
scene.worldNode.addChild(blackNode)
blackNode.alpha = 1.0
blackNode.run(SKAction.fadeOut(withDuration: 0.5)) }
I was struggling to find the solution to this, so I hope this helps someone out there. Cheers
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With