SpriteKit:淡出SKNode-子节点会透过闪烁

12

我有一个SKSpriteNode,我用 baseNode.runAction(SKAction.fadeOutWithDuration(0.5)) 淡出它

这个sprite有一个子节点。还有一个SKSpriteNode。(图中的红色块)

baseNode淡出时,会有子节点的轮廓。

避免这种情况并同时淡出整个节点和它的子节点的最佳方法是什么?我想在子节点中播放纹理动画。所以压平不是解决方案。

enter image description here


你只是想要淡化子节点吗? - sangony
不,我希望同时淡出两个节点,这样看起来就像是我只淡出了父节点。 - Jonas Ester
5个回答

6
这个问题引起了我的好奇心。我有一个解决方案,但是由于我不懂Swift,所以用Objective-C写了出来。然而,它非常简单,你应该没有问题将其移植过去。
诀窍是将整个节点“平铺”成单个纹理,然后逐渐淡化该纹理。
我使用Category实现了这一点。下面的代码将SKSpriteNode的texture属性替换为扁平化的texture。关键方法是-textureFromNode:,位于SKView类中。
@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

在非SKSpriteNode情况下,您可以将一个新的SKSpriteNode添加为被压缩节点的子节点。由于您正在制作单个纹理,因此不支持节点内部的动画。当然,您可以选择隐藏而不是删除所有子节点。如果您为已删除的纹理添加额外属性,甚至可以保存内部状态,并使用-unflatten方法恢复此方法的效果。但这超出了您的问题范围。
我在模拟器中拍摄了这张截图。请注意,节点计数器对应于3个淡化的SKSpriteNodes、1个SKLabelNode和1个压缩的精灵(SKSpriteNode)。

Non-flattened vs. flattened SKSpriteNode


真的是一个很好的解决方案。但我想用子节点播放纹理动画。不过我真的很喜欢你的答案,如果没有其他解决方案,我会给予奖励。 - Jonas Ester

1
你需要对节点的子元素调用相同的操作。
baseNode.runAction(SKAction.fadeOutWithDuration(0.5))

for node in baseNode.children as! [SKSpriteNode]
{
    node.runAction(SKAction.fadeOutWithDuration(0.5))
}

我已经尝试过这个方法。但是仍然存在子节点的亮度。我猜测这是因为两个节点的alpha值被相加了。所以如果淡出的alpha值为0.5,它们两个一起仍然有1.0的alpha值。 - Jonas Ester
如果子视图与背景颜色相同且不应该被看到,为什么不使用clearColor呢? - ZeMoon
孩子的高度比可见部分高,因为它在红色条上播放了一段纹理动画。 - Jonas Ester

1

为了在屏幕之间实现平滑的过渡效果,一个很酷的方法是使用黑色节点覆盖整个屏幕,然后淡出。我想到了以下方法: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)) }

我曾经苦苦寻找这个解决方案,所以我希望这可以帮助到其他人。谢谢。


1
你可以使用一个包含基础节点和子节点的父级SKEffectNode,并在效果节点本身上进行淡入淡出。即使您没有使用SKEffectNode的过滤器或其他功能,它也会在私有帧缓冲区中呈现其子节点,因此它最终会执行尝试平铺建议要做的事情,但它将为您处理所有内容,即使子节点每帧都在进行动画,就像您在示例中所做的那样。
为了提高性能,您还可以通过设置shouldEnableEffects = false来禁用使用父SKEffectNode的额外成本,并且只在需要进行淡入淡出时打开/关闭此选项。

0

在子节点上使用colorizeWithColor(_:colorBlendFactor:duration:),而不是fadeOutWithDuration(),如何?

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:) 创建一个动画,用于动画化精灵的颜色和混合因子。
声明 SWIFT class func colorizeWithColor(_ color: UIColor, colorBlendFactor colorBlendFactor: CGFloat, duration sec: NSTimeInterval) -> SKAction
参数 color 精灵的新颜色。 colorBlendFactor 精灵的新混合因子。 sec 动画的持续时间。
返回值 一个新的操作对象。
讨论 此操作只能由SKSpriteNode对象执行。 执行操作时,将精灵的颜色和colorBlendFactor属性动画到其新值。
此操作不可逆;该操作的反向操作无效。
导入语句 SWIFT import SpriteKit
可用性 iOS 7.0及更高版本。

我使用了 SKAction.colorizeWithColor(SKColor.clearColor(), colorBlendFactor: 1.0, duration: 1),但子节点仍然透过它显示出来。 - Jonas Ester

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接