CADisplayLink は、実際には少し... 計画している内容には十分です (画面描画の更新をカスタム アニメーションに同期させるためのものです)。これが私の解決策です:いくつかのものに火をつけてください!必ずしも爆発ではありませんが、これによりブロックが青い炎を吐き出します (変更することで色を変更できますself.fireColor
)。
- (void)checkCollisionWithBlocks
{
for (BlockView *bv in blocks) {
if (CGRectIntersectsRect(bv.frame, ballRect)) {
ballVelocity.y = -ballVelocity.y;
[blocks removeObject:bv];
[bv burpFire]
[bv removeFromSuperview];
break;
}
}
}
@interface BlockView : UIView
@property (nonatomic, strong) CALayer *rootLayer;
@property (nonatomic, strong) CAEmitterLayer *fireEmitter;
@property (nonatomic, strong) CAEmitterLayer *smokeEmitter;
@property (nonatomic, strong) UIColor *fireColor;
@property (nonatomic, strong) UIColor *smokeColor;
-(void)burpFire;
@end
@implementation BlockView
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
self.rootLayer = [CALayer layer];
//Set the root layer's background color to black
self.rootLayer.backgroundColor = [UIColor blackColor].CGColor;
//Create the fire emitter layer
self.fireEmitter = [CAEmitterLayer layer];
self.fireEmitter.emitterPosition = CGPointMake(0, CGRectGetMaxY(frame) + 50);
self.fireEmitter.emitterMode = kCAEmitterLayerOutline;
self.fireEmitter.emitterShape = kCAEmitterLayerLine;
self.fireEmitter.renderMode = kCAEmitterLayerAdditive;
self.fireEmitter.emitterSize = CGSizeMake(0, 0);
//Create the smoke emitter layer
self.smokeEmitter = [CAEmitterLayer layer];
self.smokeEmitter.emitterPosition = CGPointMake(0, CGRectGetMaxY(frame) + 50);
self.smokeEmitter.emitterMode = kCAEmitterLayerPoints;
//Create the fire emitter cell
CAEmitterCell* fire = [CAEmitterCell emitterCell];
fire.emissionLongitude = M_PI;
fire.birthRate = 0;
fire.velocity = -80;
fire.velocityRange = -30;
fire.emissionRange = -1.1;
fire.yAcceleration = -200;
fire.scaleSpeed = 0.3;
self.fireColor = [UIColor colorWithRed:0.425 green:0.779 blue:0.800 alpha:0.100];
fire.color = self.fireColor.CGColor;
fire.contents = (id)[self CGImageNamed:@"fire.png"];
//Name the cell so that it can be animated later using keypaths
[fire setName:@"fire"];
//Add the fire emitter cell to the fire emitter layer
self.fireEmitter.emitterCells = [NSArray arrayWithObject:fire] ;
//Create the smoke emitter cell
CAEmitterCell* smoke = [CAEmitterCell emitterCell];
smoke.birthRate = 11;
smoke.emissionLongitude = M_PI / 2;
smoke.lifetime = 0;
smoke.velocity = -40;
smoke.velocityRange = 20;
smoke.emissionRange = M_PI / 4;
smoke.spin = 1;
smoke.spinRange = 6;
smoke.yAcceleration = 160;
smoke.contents = (id) [self CGImageNamed:@"smoke.png"];
smoke.scale = 0.1;
smoke.alphaSpeed = -0.12;
smoke.scaleSpeed = 0.7;
//Name the cell so that it can be animated later using keypaths
[smoke setName:@"smoke"];
//Add the smoke emitter cell to the smoke emitter layer
self.smokeEmitter.emitterCells = [NSArray arrayWithObject:smoke];
//Add the two emitter layers to the root layer
[self.layer addSublayer:self.smokeEmitter];
[self.layer addSublayer:self.fireEmitter];
[self burpFire];
}
return self;
}
//Return a CGImageRef from the specified image file in the app's bundle
-(CGImageRef)CGImageNamed:(NSString*)name {
NSString *url = [[NSBundle mainBundle] pathForResource:name ofType:nil];
return [UIImage imageWithContentsOfFile:url].CGImage;
}
-(void)burpFire {
float gas = 80.0 / 100.0;
//Update the fire properties
[self.fireEmitter setValue:[NSNumber numberWithInt:(gas * 1000)] forKeyPath:@"emitterCells.fire.birthRate"];
[self.fireEmitter setValue:[NSNumber numberWithFloat:gas] forKeyPath:@"emitterCells.fire.lifetime"];
[self.fireEmitter setValue:[NSNumber numberWithFloat:(gas * 0.35)] forKeyPath:@"emitterCells.fire.lifetimeRange"];
self.fireEmitter.emitterSize = CGSizeMake(100 * gas, 0);
//Update the smoke properites
[self.smokeEmitter setValue:[NSNumber numberWithInt:gas * 4] forKeyPath:@"emitterCells.smoke.lifetime"];
self.smokeColor = [UIColor colorWithRed:1 green:1 blue:1 alpha:gas * 0.3];
[self.smokeEmitter setValue:(__bridge id)self.smokeColor.CGColor forKeyPath:@"emitterCells.smoke.color"];
[self setNeedsDisplay];
[self performSelector:@selector(burpFinished) withObject:nil afterDelay:1.5];
}
-(void)burpFinished {
float gas = 0.0 / 100.0;
//Update the fire properties
[self.fireEmitter setValue:[NSNumber numberWithInt:(gas * 1000)] forKeyPath:@"emitterCells.fire.birthRate"];
[self.fireEmitter setValue:[NSNumber numberWithFloat:gas] forKeyPath:@"emitterCells.fire.lifetime"];
[self.fireEmitter setValue:[NSNumber numberWithFloat:(gas * 0.35)] forKeyPath:@"emitterCells.fire.lifetimeRange"];
self.fireEmitter.emitterSize = CGSizeMake(100 * gas, 0);
//Update the smoke properites
[self.smokeEmitter setValue:[NSNumber numberWithInt:gas * 4] forKeyPath:@"emitterCells.smoke.lifetime"];
self.smokeColor = [UIColor colorWithRed:1 green:1 blue:1 alpha:gas * 0.3];
[self.smokeEmitter setValue:(__bridge id)self.smokeColor.CGColor forKeyPath:@"emitterCells.smoke.color"];
}
CAEmitterLayers はかなりの時間持続するため、火を少し早く消したい場合は、ストップ セレクターのタイミングを調整します。火を小さくしたり大きくしたり、火の玉を長く放ちたい場合は、init メソッドのプロパティをいじってみてください。いずれにしても、クールな効果が得られます。
すべての色は UIColor への強力な参照である必要があります。そうしないと、Core Animation がおかしくなり、デバッガーで C++ の癇癪を起こしてしまいます...不快です。