2014-03-18 48 views
19

如何在SpriteKit的SKScene中为所有节点添加高斯模糊(没有固定数量的节点)?稍后会在场景顶部添加标签,这将是我的暂停菜单。 几乎任何事情都会有所帮助!如何在SpriteKit中模糊场景?

像这样的东西是什么,我去为: Gaussian pause menu

+0

您可能会发现此链接有用:[http://eppz.eu/blog/create-ios-7-blur-effect/](http://eppz.eu/blog/create-ios-7-blur -effect /) – JKallio

+0

不,我不想导入任何东西,我希望它是全部SKScene,我不能使用UIView中的任何东西 –

回答

30

什么你要找的是一个SKEffectNode。它将CoreImage过滤器应用于自身(以及所有子节点)。只要将它作为场景的根视图,给它一个CoreImage的模糊滤镜,然后设置好。

例如,我建立了一个SKSceneSKEffectNode,因为它是第一个子节点和属性,root保持一个弱引用时:

-(void)createLayers{ 
    SKEffectNode *node = [SKEffectNode node]; 
    [node setShouldEnableEffects:NO]; 
    CIFilter *blur = [CIFilter filterWithName:@"CIGaussianBlur" keysAndValues:@"inputRadius", @1.0f, nil]; 
    [node setFilter:blur]; 
    [self setRoot:node]; 
} 

这里是我用来(动画的方法! )我的场景的模糊:

-(void)blurWithCompletion:(void (^)())handler{ 
    CGFloat duration = 0.5f; 
    [[self root] setShouldRasterize:YES]; 
    [[self root] setShouldEnableEffects:YES]; 
    [[self root] runAction:[SKAction customActionWithDuration:duration actionBlock:^(SKNode *node, CGFloat elapsedTime){ 
    NSNumber *radius = [NSNumber numberWithFloat:(elapsedTime/duration) * 10.0]; 
    [[(SKEffectNode *)node filter] setValue:radius forKey:@"inputRadius"]; 
    }] completion:handler]; 
} 

需要注意的是,像你一样,我用这个作为一个暂停画面,所以我栅格化的场景。如果你希望你的场景在模糊的时候进行动画制作,你应该可以使用setShouldResterize:NO

如果你不感兴趣的动画过渡到模糊,你总是可以只过滤器设置为10.0f左右的初始半径,做一个简单的setShouldEnableEffects:YES当你想打开它。

参见:SKEffectNode class reference

更新:下面
见马库斯的评论。他指出SKScene实际上是SKEffectNode的一个子类,所以你真的应该能够在场景中调用所有这些,而不是在节点树中任意插入一个效果节点。

+0

你是如何将节点添加为孩子的? [self addChild:node]; //它会抛出一个错误=>(lldb) 是否将示例输入到ViewController? –

+0

我真的不明白错误在哪里。 这是我的代码,http://postimg.org/image/bg8qb70rp/ 它不显示任何错误,但它也不显示任何操作。 –

+0

哦,我发现这个问题,它不适用于我Restarized YES .. –

9

这是我对暂停屏幕的解决方案。 它会截图,模糊它,然后用动画显示它。 我认为你应该这样做,如果你不想浪费到太多的fps。

-(void)pause { 
    SKSpriteNode *pauseBG = [SKSpriteNode spriteNodeWithTexture:[SKTexture textureWithImage:[self getBluredScreenshot]]]; 
    pauseBG.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame)); 
    pauseBG.alpha = 0; 
    pauseBG.zPosition = 2; 
    [pauseBG runAction:[SKAction fadeAlphaTo:1 duration:duration/2]]; 
    [self addChild:pauseBG]; 
} 

这是辅助方法:

- (UIImage *)getBluredScreenshot { 
    UIGraphicsBeginImageContextWithOptions(self.view.bounds.size, NO, 1); 
    [self.view drawViewHierarchyInRect:self.view.frame afterScreenUpdates:YES]; 
    UIImage *ss = UIGraphicsGetImageFromCurrentImageContext(); 
    UIGraphicsEndImageContext(); 

    CIFilter *gaussianBlurFilter = [CIFilter filterWithName:@"CIGaussianBlur"]; 
    [gaussianBlurFilter setDefaults]; 
    [gaussianBlurFilter setValue:[CIImage imageWithCGImage:[ss CGImage]] forKey:kCIInputImageKey]; 
    [gaussianBlurFilter setValue:@10 forKey:kCIInputRadiusKey]; 

    CIImage *outputImage = [gaussianBlurFilter outputImage]; 
    CIContext *context = [CIContext contextWithOptions:nil]; 
    CGRect rect   = [outputImage extent]; 
    rect.origin.x  += (rect.size.width - ss.size.width)/2; 
    rect.origin.y  += (rect.size.height - ss.size.height)/2; 
    rect.size   = ss.size; 
    CGImageRef cgimg  = [context createCGImage:outputImage fromRect:rect]; 
    UIImage *image  = [UIImage imageWithCGImage:cgimg]; 
    CGImageRelease(cgimg); 
    return image; 
} 
+2

有点太晚的项目,但我会保留它以备将来参考:) 非常感谢! –

+0

欢迎您:) –

+0

完美作品,谢谢! – StackBuddy

11

要使用@Bendegúz的答案和代码http://www.bytearray.org/?p=5360

我能得到这个在我目前的游戏工作添加到此这个项目正在IOS 8 Swift中完成。通过返回一个SKSpriteNode而不是一个UIImage来完成一点。另请注意,我的解包currentScene.view!调用是一个弱GameScene引用,但应根据您调用这些方法的位置与self.view.frame一起工作。我的暂停屏幕在单独的HUD类中被调用,因此为何如此。

我想这可能会做得更优雅,也许更像是@ jemmons的答案。只是想帮助其他人试图在所有或某些Swift代码中编写SpriteKit项目。

func getBluredScreenshot() -> SKSpriteNode{ 

    create the graphics context 
    UIGraphicsBeginImageContextWithOptions(CGSize(width: currentScene.view!.frame.size.width, height: currentScene.view!.frame.size.height), true, 1) 

    currentScene.view!.drawViewHierarchyInRect(currentScene.view!.frame, afterScreenUpdates: true) 

    // retrieve graphics context 
    let context = UIGraphicsGetCurrentContext() 

    // query image from it 
    let image = UIGraphicsGetImageFromCurrentImageContext() 

    // create Core Image context 
    let ciContext = CIContext(options: nil) 
    // create a CIImage, think of a CIImage as image data for processing, nothing is displayed or can be displayed at this point 
    let coreImage = CIImage(image: image) 
    // pick the filter we want 
    let filter = CIFilter(name: "CIGaussianBlur") 
    // pass our image as input 
    filter.setValue(coreImage, forKey: kCIInputImageKey) 

    //edit the amount of blur 
    filter.setValue(3, forKey: kCIInputRadiusKey) 

    //retrieve the processed image 
    let filteredImageData = filter.valueForKey(kCIOutputImageKey) as CIImage 
    // return a Quartz image from the Core Image context 
    let filteredImageRef = ciContext.createCGImage(filteredImageData, fromRect: filteredImageData.extent()) 
    // final UIImage 
    let filteredImage = UIImage(CGImage: filteredImageRef) 

    // create a texture, pass the UIImage 
    let texture = SKTexture(image: filteredImage!) 
    // wrap it inside a sprite node 
    let sprite = SKSpriteNode(texture:texture) 

    // make image the position in the center 
    sprite.position = CGPointMake(CGRectGetMidX(currentScene.frame), CGRectGetMidY(currentScene.frame)) 

    var scale:CGFloat = UIScreen.mainScreen().scale 

    sprite.size.width *= scale 

    sprite.size.height *= scale 

    return sprite 


} 


func loadPauseBGScreen(){ 

    let duration = 1.0 

    let pauseBG:SKSpriteNode = self.getBluredScreenshot() 

    //pauseBG.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame)) 
    pauseBG.alpha = 0 
    pauseBG.zPosition = self.zPosition + 1 
    pauseBG.runAction(SKAction.fadeAlphaTo(1, duration: duration)) 

    self.addChild(pauseBG) 

} 
+2

查克,标签上写着objective-c。 –

2

这是获得此斯威夫特2完成,无需层层另一个例子:

func blurWithCompletion() { 
let duration: CGFloat = 0.5 
let filter: CIFilter = CIFilter(name: "CIGaussianBlur", withInputParameters: ["inputRadius" : NSNumber(double:1.0)])! 
scene!.filter = filter 
scene!.shouldRasterize = true 
scene!.shouldEnableEffects = true 
scene!.runAction(SKAction.customActionWithDuration(0.5, actionBlock: { (node: SKNode, elapsedTime: CGFloat) in 
    let radius = (elapsedTime/duration)*10.0 
    (node as? SKEffectNode)!.filter!.setValue(radius, forKey: "inputRadius") 

})) 

}

1

斯威夫特3更新:这@Chuck加夫尼的回答更新的斯威夫特3 。我知道这个问题被标记为objective-c,但是这个页面在Google中名列第二,因为“swritekit blur”很快。我将currentScene更改为self

func getBluredScreenshot() -> SKSpriteNode{ 

    //create the graphics context 
    UIGraphicsBeginImageContextWithOptions(CGSize(width: self.view!.frame.size.width, height: self.view!.frame.size.height), true, 1) 

    self.view!.drawHierarchy(in: self.view!.frame, afterScreenUpdates: true) 

    // retrieve graphics context 
    _ = UIGraphicsGetCurrentContext() 

    // query image from it 
    let image = UIGraphicsGetImageFromCurrentImageContext() 

    // create Core Image context 
    let ciContext = CIContext(options: nil) 
    // create a CIImage, think of a CIImage as image data for processing, nothing is displayed or can be displayed at this point 
    let coreImage = CIImage(image: image!) 
    // pick the filter we want 
    let filter = CIFilter(name: "CIGaussianBlur") 
    // pass our image as input 
    filter?.setValue(coreImage, forKey: kCIInputImageKey) 

    //edit the amount of blur 
    filter?.setValue(3, forKey: kCIInputRadiusKey) 

    //retrieve the processed image 
    let filteredImageData = filter?.value(forKey: kCIOutputImageKey) as! CIImage 
    // return a Quartz image from the Core Image context 
    let filteredImageRef = ciContext.createCGImage(filteredImageData, from: filteredImageData.extent) 
    // final UIImage 
    let filteredImage = UIImage(cgImage: filteredImageRef!) 

    // create a texture, pass the UIImage 
    let texture = SKTexture(image: filteredImage) 
    // wrap it inside a sprite node 
    let sprite = SKSpriteNode(texture:texture) 

    // make image the position in the center 
    sprite.position = CGPoint(x: self.frame.midX, y: self.frame.midY) 

    let scale:CGFloat = UIScreen.main.scale 

    sprite.size.width *= scale 

    sprite.size.height *= scale 

    return sprite 


} 

func loadPauseBGScreen(){ 

    let duration = 1.0 

    let pauseBG:SKSpriteNode = self.getBluredScreenshot() 

    pauseBG.alpha = 0 
    pauseBG.zPosition = self.zPosition + 1 
    pauseBG.run(SKAction.fadeAlpha(to: 1, duration: duration)) 

    self.addChild(pauseBG) 

} 
0

斯威夫特4:当你想用它

let blur = CIFilter(name:"CIGaussianBlur",withInputParameters: ["inputRadius": 10.0]) 
     self.filter = blur 
     self.shouldRasterize = true 
     self.shouldEnableEffects = false 

变化self.shouldEnableEffects =真:

这一点,如果你想在场景中的一切模糊添加到您的gameScene 。