你怎么能通过SKEffectNode创build一个精灵周围的辉光

我有一个SKSpriteNode ,我想围绕它的边缘蓝色辉光突出的目的。 我猜测,我需要使我的精灵成为一个SKEffectNode的孩子,然后创build/应用某种filter。

更新:我已经调查了这与select的答案的方法相当,并发现SKEffectNode具有相当大的性能,即使你已经设置了shouldRasterize和'没有filter'定义。 我的结论是,如果你的游戏一次需要超过10个移动对象,即使被光栅化,它们也不能涉及SKEffectNode

我的解决scheme可能会涉及预先呈现的辉光图像/animation,因为SKEffectNode不会根据我的要求来裁减它。

如果有人对我错过的任何东西有所了解,我会很高兴听到你所知道的任何事情!

我正在接受一个答案,因为它确实实现了我所要求的答案,但是希望将这些注释添加到正在寻找此路线的任何人,以便您了解使用SKEffectNode的一些问题。

@ rickster的答案是伟大的。 由于我代表低代表,我显然不允许添加此代码作为他的评论。 我希望这不会违反礼仪的叠加规则。 我不想以任何方式使用他的代表。

这里是他在回答中描述的代码:

标题:

 // ENHGlowFilter.h #import <CoreImage/CoreImage.h> @interface ENHGlowFilter : CIFilter @property (strong, nonatomic) UIColor *glowColor; @property (strong, nonatomic) CIImage *inputImage; @property (strong, nonatomic) NSNumber *inputRadius; @property (strong, nonatomic) CIVector *inputCenter; @end //Based on ASCGLowFilter from Apple 

执行:

 #import "ENHGlowFilter.h" @implementation ENHGlowFilter -(id)init { self = [super init]; if (self) { _glowColor = [UIColor whiteColor]; } return self; } - (NSArray *)attributeKeys { return @[@"inputRadius", @"inputCenter"]; } - (CIImage *)outputImage { CIImage *inputImage = [self valueForKey:@"inputImage"]; if (!inputImage) return nil; // Monochrome CIFilter *monochromeFilter = [CIFilter filterWithName:@"CIColorMatrix"]; CGFloat red = 0.0; CGFloat green = 0.0; CGFloat blue = 0.0; CGFloat alpha = 0.0; [self.glowColor getRed:&red green:&green blue:&blue alpha:&alpha]; [monochromeFilter setDefaults]; [monochromeFilter setValue:[CIVector vectorWithX:0 Y:0 Z:0 W:red] forKey:@"inputRVector"]; [monochromeFilter setValue:[CIVector vectorWithX:0 Y:0 Z:0 W:green] forKey:@"inputGVector"]; [monochromeFilter setValue:[CIVector vectorWithX:0 Y:0 Z:0 W:blue] forKey:@"inputBVector"]; [monochromeFilter setValue:[CIVector vectorWithX:0 Y:0 Z:0 W:alpha] forKey:@"inputAVector"]; [monochromeFilter setValue:inputImage forKey:@"inputImage"]; CIImage *glowImage = [monochromeFilter valueForKey:@"outputImage"]; // Scale float centerX = [self.inputCenter X]; float centerY = [self.inputCenter Y]; if (centerX > 0) { CGAffineTransform transform = CGAffineTransformIdentity; transform = CGAffineTransformTranslate(transform, centerX, centerY); transform = CGAffineTransformScale(transform, 1.2, 1.2); transform = CGAffineTransformTranslate(transform, -centerX, -centerY); CIFilter *affineTransformFilter = [CIFilter filterWithName:@"CIAffineTransform"]; [affineTransformFilter setDefaults]; [affineTransformFilter setValue:[NSValue valueWithCGAffineTransform:transform] forKey:@"inputTransform"]; [affineTransformFilter setValue:glowImage forKey:@"inputImage"]; glowImage = [affineTransformFilter valueForKey:@"outputImage"]; } // Blur CIFilter *gaussianBlurFilter = [CIFilter filterWithName:@"CIGaussianBlur"]; [gaussianBlurFilter setDefaults]; [gaussianBlurFilter setValue:glowImage forKey:@"inputImage"]; [gaussianBlurFilter setValue:self.inputRadius ?: @10.0 forKey:@"inputRadius"]; glowImage = [gaussianBlurFilter valueForKey:@"outputImage"]; // Blend CIFilter *blendFilter = [CIFilter filterWithName:@"CISourceOverCompositing"]; [blendFilter setDefaults]; [blendFilter setValue:glowImage forKey:@"inputBackgroundImage"]; [blendFilter setValue:inputImage forKey:@"inputImage"]; glowImage = [blendFilter valueForKey:@"outputImage"]; return glowImage; } @end 

正在使用:

 @implementation ENHMyScene //SKScene subclass -(id)initWithSize:(CGSize)size { if (self = [super initWithSize:size]) { /* Setup your scene here */ [self setAnchorPoint:(CGPoint){0.5, 0.5}]; self.backgroundColor = [SKColor colorWithRed:0.15 green:0.15 blue:0.3 alpha:1.0]; SKEffectNode *effectNode = [[SKEffectNode alloc] init]; ENHGlowFilter *glowFilter = [[ENHGlowFilter alloc] init]; [glowFilter setGlowColor:[[UIColor redColor] colorWithAlphaComponent:0.5]]; [effectNode setShouldRasterize:YES]; [effectNode setFilter:glowFilter]; [self addChild:effectNode]; _effectNode = effectNode; } return self; } -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { /* Called when a touch begins */ for (UITouch *touch in touches) { CGPoint location = [touch locationInNode:self]; SKSpriteNode *sprite = [SKSpriteNode spriteNodeWithImageNamed:@"Spaceship"]; sprite.position = location; [self.effectNode addChild:sprite]; } } 

您可以通过创build组成多个内置filter的CIFilter子类来在Core Image中创build发光效果。 这样的filter将涉及这样的步骤:

  1. 创build一个图像用作蓝色的光芒。 可能有几个体面的方法来做到这一点; 一种是使用CIColorMatrix创buildinput图像的单色版本。
  2. 放大并模糊辉光图像( CIAffineTransform + CIGaussianBlur )。
  3. 将原始input图像复合到辉光图像上( CISourceOverCompositing )。

一旦你有一个CIFilter子类,就可以用它来和SKEffectNode一起在效果节点的子节点周围获得一个实时的发光。 在这里它运行在iPad 4上的“Sprite Kit Game”Xcode模板中:

Sprite Kit中的发光太空船

通过在WWDC 2013的Scene Kit演示文件中使用类似效果的自定义filter类,在几分钟内完成了此操作,然后从developer.apple.com/downloads上的WWDC示例代码包中抓取它,并查看为ASCGlowFilter类。 (如果你想在iOS上使用这个代码,你需要改变NSAffineTransform部分来使用CGAffineTransform而我也用一个types为CIVectorinputCenter参数replace了centerXcenterY属性,所以Sprite Kit可以自动的将效果集中到精灵)。

我说“实时”发光吗? 对! 这是“真的吃CPU时间”的简称。 注意截图中不再固定在60 fps,即使只有一个太空船 – 在iOS模拟器上使用软件OpenGL ES渲染器,它将以幻灯片速度运行。 如果你在Mac上,你可能会有硅片,但是如果你想在游戏中这样做,记住一些事情:

  • 可能有一些方法可以从filter本身获得更好的性能。 玩不同的CI滤镜,你可能会看到一些改进(核心图像有几个模糊滤镜,其中一些肯定会比高斯快)。 另外请注意,模糊效果往往是片段着色器边界,所以图像越小,发光半径越小越好。
  • 如果你想在一个场景中有多个发光,可以考虑让同一个效果节点上的所有发光的小精灵 – 将它们全部渲染成一个图像,然后应用一次滤镜。
  • 如果发光的精灵变化不大(例如,如果我们的太空飞船没有旋转), shouldRasterize在效果节点上设置为YES就应该有很大的帮助。 (实际上,在这种情况下,您可能会通过旋转效果节点而不是其中的精灵来获得一些改进。)
  • 你真的需要实时发光吗? 与游戏中许多炫目的graphics效果一样,如果你假冒它,你会获得更好的性能。 在你最喜欢的graphics编辑器中制作一个模糊,蓝色的飞船,并把它放在场景中作为另一个精灵。

您可以在Sprite后面使用SKShapeNode ,并使用它的glowWidthstrokeColor属性定义辉光。 如果你的尺寸和位置正确,这应该会给你一个焕发的外观。 这并没有给你很多定制的select,但是我想这比使用一个CIFilterSKEffectNode要容易得多,这可能是你的另一个逻辑选项。