強調表示の目的で、エッジの周りに青い輝きを持たせたいSKSpriteNode
があります。スプライトをSKEffectNode
の子にしてから、ある種のフィルターを作成/適用する必要があると思います。
更新:選択した回答のアプローチでこれをかなり調査したところ、SKEffectNode
に設定し、「フィルターなし」を定義した場合でも、shouldRasterize
のパフォーマンスに大きな影響があることがわかりました。私の結論は、ゲームで一度に10を超える移動オブジェクトが必要な場合、ラスタライズされていてもSKEffectNode
を含めることはできないということです。
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];
}
}
複数の組み込みフィルターを構成するCIFilter
サブクラスを作成することにより、CoreImageでグロー効果を作成できます。このようなフィルターには、次のような手順が含まれます。
CIColorMatrix
を使用して、モノクロバージョンの入力画像を作成することです。CIAffineTransform
+ CIGaussianBlur
)。CISourceOverCompositing
)に合成します。それをすべて行うCIFilter
サブクラスができたら、それをSKEffectNode
と一緒に使用して、エフェクトノードの子の周りをリアルタイムでグローさせることができます。ここでは、iPad4の「SpriteKitGame」Xcodeテンプレートで実行されています。
WWDC 2013からのシーンキットプレゼンテーションで同様の効果に使用されるカスタムフィルタークラスをクリブすることで、これを数分で起動して実行しました- developer.Apple.com/にあるWWDCサンプルコードパッケージから取得しますdownloads 、そしてASCGlowFilter
クラスを探します。 (iOSでそのコードを使用する場合は、代わりにNSAffineTransform
部分をCGAffineTransform
を使用するように変更する必要があります。また、centerX
プロパティとcenterY
プロパティをinputCenter
タイプのCIVector
パラメーターに置き換えて、スプライトキットが自動的にスプライト。)
「リアルタイム」の輝きを言ったか。うん!これは「CPU時間を本当に消費する」の略です。スクリーンショットでは、宇宙船が1つしかない場合でも60 fpsで固定されていないことに注意してください。iOSシミュレーターのソフトウェアOpenGL ESレンダラーを使用すると、スライドショーの速度で実行されます。 Macを使用している場合は、おそらく余裕のあるシリコンがありますが、ゲームでこれを実行する場合は、いくつかの点に注意してください。
shouldRasterize
をYES
に設定すると非常に役立ちます。 (実際には、この場合、スプライトの代わりにエフェクトノードを回転させることで改善が得られる可能性があります。)スプライトの背後でSKShapeNode
を使用し、そのglowWidth
プロパティとstrokeColor
プロパティを使用してグローを定義できます。サイズと位置を正しく設定すると、輝きのようになります。これはカスタマイズのための多くのオプションを提供しませんが、CIFilter
をSKEffectNode
と一緒に使用するよりもはるかに簡単であろうと思います。