Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SpriteKit: fade out SKNode - children shines through

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.

enter image description here

like image 505
Jonas Ester Avatar asked Apr 10 '15 23:04

Jonas Ester


4 Answers

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.

like image 138
Jeff Adams Avatar answered Nov 17 '22 11:11

Jeff Adams


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).

Non-flattened vs. flattened SKSpriteNode

like image 41
CloakedEddy Avatar answered Nov 17 '22 12:11

CloakedEddy


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))
}
like image 1
ZeMoon Avatar answered Nov 17 '22 12:11

ZeMoon


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

like image 1
Jonathan Bencomo Avatar answered Nov 17 '22 13:11

Jonathan Bencomo