11
votes

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

5
Are you looking to just fade the child node?sangony
No, I want to fade out both Nodes simultaneously. So that it looks like I just fade out the parent node.Jonas Ester

5 Answers

6
votes

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

1
votes

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))
}
1
votes

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.

1
votes

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

0
votes

Instead of fadeOutWIthDuration() on the child nodes, why don't you use colorizeWithColor(_:colorBlendFactor:duration:).

https://developer.apple.com/library/prerelease/ios/documentation/SpriteKit/Reference/SKAction_Ref/index.html#//apple_ref/occ/clm/SKAction/colorizeWithColor:colorBlendFactor:duration:

colorizeWithColor(_:colorBlendFactor:duration:)

Creates an animation that animates a sprite’s color and blend factor.

Declaration

SWIFT

class func colorizeWithColor(_ color: UIColor, colorBlendFactor colorBlendFactor: CGFloat, duration sec: NSTimeInterval) -> SKAction

Parameters

color The new color for the sprite.

colorBlendFactor The new blend factor for the sprite.

sec The duration of the animation.

Return Value A new action object.

Discussion This action can only be executed by an SKSpriteNode object. When the action executes, the sprite’s color and colorBlendFactor properties are animated to their new values.

This action is not reversible; the reverse of this action does nothing.

Import Statement

SWIFT

import SpriteKit

Availability Available in iOS

7.0 and later.