iOSでパーティクルエフェクトを表現する際は、Sprite Kitが主流のようですが、今回はもっとお手軽にCoreAnimation(CAEmitterLayer / CAEmitterCell)でかつシミュレーションアプリ「Particle Playground」で実装してみたいと思います。
(ほとんどコード書きません。)
CAEmitterLayer / CAEmitterCellの概要
iOS5よりCoreAnimationでサポートされたパーティクルシステムです。
UIKit上でお手軽にパーティクルエフェクトを実装することができます。
Particle Playgroundについて
CoreAnimationのパーティクルエフェクトを手軽に試すことができ、
なんとソースコード(Objective-C)も書き出してくれるMac用アプリケーションです。
AppStoreで購入することができ、お値段は約1,000円。
(動きの微調整を節約できるためおそらくお安い方だと思います。。)
実装
今回は簡単な星空のエフェクトを作ってみたいと思います。
星がキラキラと明滅するようなエフェクトです。
素材はこちらを使用しました。(わかりやすくするため、ここでは背景を黒にしています。)
手順は以下のとおり。
1. Particle Playgroundで動きの調整(エフェクトにこだわらなければ2min)
2. Particle Playgroundでソースコード書き出し(1min)
3. Xcode Project に転記(2min)
これだけです。
1. Particle Playgroundで動きの調整(2min)
まずはParticle Playgroundでパラメータを調整し、理想のアニメーションに近づけていきます。
UI上でパラメータをいじるだけですので、特にコードは打つことはありません。
画像をParticleImageの部分にドラッグ&ドロップするれば、その画像でParticleが生成されます。
以下、調整した値となります。
2. Particle Playgroundでソースコード書き出し(1min)
左上の「Export」ボタンを押すと、.m形式で書き出してくれます。
書き出されたコードは以下の通りです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 |
// // PPEmitterView.h // Created by Particle Playground // #import "PPEmitterView.h" @implementation PPEmitterView -(id)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { self.backgroundColor = [UIColor clearColor]; } return self; } -(id)initWithCoder:(NSCoder *)aDecoder { self = [super initWithCoder:aDecoder]; if (self) { self.backgroundColor = [UIColor clearColor]; } return self; } + (Class) layerClass { //configure the UIView to have emitter layer return [CAEmitterLayer class]; } -(void)awakeFromNib { CAEmitterLayer *emitterLayer = (CAEmitterLayer*)self.layer; emitterLayer.name = @"emitterLayer"; emitterLayer.emitterPosition = CGPointMake(160, 240); emitterLayer.emitterZPosition = 0; emitterLayer.emitterSize = CGSizeMake(400.00, 400.00); emitterLayer.emitterDepth = 0.00; emitterLayer.emitterShape = kCAEmitterLayerCircle; emitterLayer.renderMode = kCAEmitterLayerOldestLast; emitterLayer.seed = 2806229524; // Create the emitter Cell CAEmitterCell *emitterCell = [CAEmitterCell emitterCell]; emitterCell.name = @"untitled"; emitterCell.enabled = YES; emitterCell.contents = (id)[[UIImage imageNamed:@"star1.png"] CGImage]; emitterCell.contentsRect = CGRectMake(0.00, 0.00, 1.00, 1.00); emitterCell.magnificationFilter = kCAFilterLinear; emitterCell.minificationFilter = kCAFilterLinear; emitterCell.minificationFilterBias = 1.00; emitterCell.scale = 1.22; emitterCell.scaleRange = 0.00; emitterCell.scaleSpeed = 0.00; emitterCell.color = [[UIColor colorWithRed:1.00 green:1.00 blue:1.00 alpha:1.00] CGColor]; emitterCell.redRange = 0.00; emitterCell.greenRange = 0.00; emitterCell.blueRange = 0.00; emitterCell.alphaRange = 1.00; emitterCell.redSpeed = 0.00; emitterCell.greenSpeed = 0.00; emitterCell.blueSpeed = 0.00; emitterCell.alphaSpeed = -0.72; emitterCell.lifetime = 5.37; emitterCell.lifetimeRange = 0.00; emitterCell.birthRate = 38; emitterCell.velocity = 0.00; emitterCell.velocityRange = 0.00; emitterCell.xAcceleration = 0.00; emitterCell.yAcceleration = 0.00; emitterCell.zAcceleration = 0.00; // these values are in radians, in the UI they are in degrees emitterCell.spin = 0.000; emitterCell.spinRange = 0.000; emitterCell.emissionLatitude = 0.000; emitterCell.emissionLongitude = 0.000; emitterCell.emissionRange = 6.283; emitterLayer.emitterCells = @[emitterCell]; } @end |
3. Swiftに転記(2min)
Particle Playgroundで書き出したコードをSwiftに転記していきます。
必要な部分のみを転記していけば数行で済んでしまいます。
Particle Playgroundでは表示領域がシミュレータに合わせてた数値が書き出されてしまうため、
これを実際に表示する画面に合わせてSizeを設定します。
修正箇所はその部分だけです。
以下コードとなります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
import UIKit class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view, typically from a nib. configureCAEmitterLayer() } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } private func configureCAEmitterLayer() { let emitterLayer = CAEmitterLayer() let size = view.bounds.size // emitterLayerの設定 emitterLayer.emitterSize = size emitterLayer.emitterPosition = CGPoint(x: size.width / 2, y: size.height / 2) emitterLayer.emitterShape = kCAEmitterLayerRectangle emitterLayer.renderMode = kCAEmitterLayerOldestLast // 表示させたいviewのlayerにadd view.layer.addSublayer(emitterLayer) // emitterCell let emitterCell = CAEmitterCell() emitterCell.contents = UIImage(named: "star")?.cgImage emitterCell.magnificationFilter = kCAFilterLinear; emitterCell.minificationFilter = kCAFilterLinear; emitterCell.minificationFilterBias = 1.00; emitterCell.scale = 1.22; emitterCell.scaleRange = 0.00; emitterCell.scaleSpeed = 0.00; emitterCell.color = UIColor.white.cgColor emitterCell.redRange = 0.00; emitterCell.greenRange = 0.00; emitterCell.blueRange = 0.00; emitterCell.alphaRange = 1.00; emitterCell.redSpeed = 0.00; emitterCell.greenSpeed = 0.00; emitterCell.blueSpeed = 0.00; emitterCell.alphaSpeed = -0.72; emitterCell.lifetime = 5.37; emitterCell.lifetimeRange = 0.00; emitterCell.birthRate = 38; emitterCell.velocity = 0.00; emitterCell.velocityRange = 0.00; emitterCell.xAcceleration = 0.00; emitterCell.yAcceleration = 0.00; emitterCell.zAcceleration = 0.00; emitterCell.spin = 0.000; emitterCell.spinRange = 0.000; emitterCell.emissionLatitude = 0.000; emitterCell.emissionLongitude = 0.000; emitterCell.emissionRange = 6.283; emitterLayer.emitterCells = [emitterCell] } } |
動作確認
Simulator上で確認してみます。
最後に
このようにパーティクルエフェクトを短時間で制作することができました。
Particle Playgroundを使えば、都度Xcode上でデバッグ→確認→調整する時間が省け、より理想的な動きに最短ルートで辿りつくことが可能です。Sprite Kitなどに比べれば動きやイージングなどの自由度は少ないですが、動きがシンプルなエフェクトであればCoreAnimation(CAEmitterLayer / CAEmitterCell)で十分表現可能です。