Swiftでパーティクルの描画☆*:.。.([CAEmitterLayer / CAEmitterCell] ※SpriteKitは使いません)
はじめまして!PR TIMES エンジニアの宇佐見です。
今年の1月にPR TIMESの開発チームにJOINしまして、主にサーバーサイドの開発に携わっています。
簡単に自己紹介させていただきますと・・・
JOINする前はエンジニアとしてFlash/FlexによるRIAやサーバーサイドの開発、WEBデザイナーというポジションでデザインしたり時には紙媒体のイラストを描いたりしていました。
直近ではiOS/MacOSのアプリケーション開発を得意とする企業さまにてアプリ開発をしていまして、技術書籍を出されている社長さま直々に開発の極意を日々叩き込まれながらアプリ開発の楽しさを感じていました。
PR TIMESでもアプリの開発に携われるといいなとこっそり思っています。
前置きが長くなりましたが・・・
初投稿となる記事は、私の大好きなキラキラ☆*:.。. した演出、パーティクルの描画をSwiftで実装してみたいと思います。パーティクルを描画する方法として、自前でアニメーションを作ったりiOS7から追加されたSpriteKitを使ったりといろいろありますが、今回はSwiftでiOS5から追加されたCAEmitterLayerとCAEmitterCellを使ってパーティクルを描画します。
なぜ今iOS5で追加されたものを??と思われてしまいそうですが、CAEmitterLayerとCAEmitterCellについての情報がiOS5から登場しているものの少なく、Swiftでの実装については現時点ではあまり無いようでしたので、今回ご紹介したいと思いました。
では早速、CAEmitterLayerとCAEmitterCellの概要を確認して実装していきます。
概要
CAEmitterLayerの生成の例
// Create emitter let emitter = CAEmitterLayer() emitter.emitterPosition = CGPointMake(100.0, 100.0) emitter.emitterSize = CGSizeMake(50.0, 50.0) emitter.emitterMode = kCAEmitterLayerOutline emitter.emitterShape = kCAEmitterLayerLine emitter.renderMode = kCAEmitterLayerAdditive
CAEmitterCellの生成の例
// Create emitter cell let emitterCell = CAEmitterCell() emitterCell.name = "fire" emitterCell.birthRate = 100 emitterCell.velocity = -80 emitterCell.velocityRange = 30 emitterCell.emissionRange = 1.1 emitterCell.scaleSpeed = 0.3 emitterCell.lifetime = 50 emitterCell.lifetimeRange = (50.0 * 0.35) emitterCell.color = UIColor(red:0.7, green:0.3, blue:0.1, alpha:0.1).CGColor emitterCell.alphaSpeed = -0.1 / (emitterCell.lifetime * 2.0)
CAEmitterCellの主要なプロパティ
- birthRate 1秒間に生成するパーティクルの数
- lifetime パーティクルが消えるまでの時間(単位:秒)
- lifetimeRange 生成された各パーティクルのlifetimeをランダムに設定するための変動の幅
- color パーティクルの色
- contents セルに使うコンテンツ(主に画像を指定)
- name セルの名前
- velocity パーティクルの秒速
- velocityRange 生成された各パーティクルのvelocityをランダムに設定するための変動の幅
- emissionRange セルを移動する際の角度(弧度)
- scaleSpeed 1秒間に変えるパーティクルのスケール
- spin 生成された各パーティクルの回転するスピード
今回は以下の3つのパーティクルを作りますので、それぞれのパーティクル用に「星」「ハート」「炎」の3つの画像を用意します。
- 星がキラキラと放出する
- ハートがフワフワと浮かぶ
- 炎がメラメラと燃える
絵的にさみしくなりそうでしたので、3人の女の子に登場していただくことにしました。
Xcodeでプロジェクトを1つ作成します。今回はSwiftでの実装になるのでプログラミング言語に「Swift」を選択します。
UITabBarControllerでそれぞれのパーティクルを描画した画面を切り替えたいと思うので、テンプレートに「Tabbed Application」を選択しました。
プロジェクトを作成したら、3つのUIViewControllerを用意して、UITabBarControllerで切り替えられるようにStoryBoardで設定します。
※UIViewControllerの作成やStoryBoardの設定などについては今回は割愛させていただきます。
それではプログラムを書いていきます。
CAEmitterLayerとCAEmitterCellはQuartzCore Frameworkのクラスで、Objective-cで実装していた時はQuartzCore Frameworkのインポートが必須でした。
Swiftではインポートしなくても正常に動作しているところをみるとインポートは不要のようです。
import QuartzCore
※ ↑ こちらは不要です
StarViewController.swiftを開いて、viewDidLoad()内に以下のソースを記述します。
viewDidLoad()内
self.emitterLayer = CAEmitterLayer() self.emitterLayer.emitterPosition = CGPointMake(self.view.bounds.size.width / 2.0, self.view.bounds.size.height / 2.0) self.emitterLayer.emitterSize = CGSizeMake(self.view.bounds.size.width / 2.0, 50.0) self.emitterLayer.emitterMode = kCAEmitterLayerVolume self.emitterLayer.emitterShape = kCAEmitterLayerRectangle self.emitterLayer.renderMode = kCAEmitterLayerAdditive let emitterCell = CAEmitterCell() emitterCell.name = "star" emitterCell.emissionLongitude = (CGFloat)(M_PI/2.0) emitterCell.emissionRange = (CGFloat)(0.55 * M_PI) emitterCell.birthRate = 0.0 emitterCell.lifetime = 10.0 emitterCell.velocity = -120 emitterCell.velocityRange = 60 emitterCell.yAcceleration = 20 emitterCell.contents = UIImage(named:"star")!.CGImage emitterCell.color = UIColor(red:0.0, green:0.5, blue:0.5, alpha:0.5).CGColor emitterCell.greenRange = 0.3 emitterCell.blueRange = 0.3 emitterCell.alphaSpeed = -0.5 / emitterCell.lifetime emitterCell.scale = 0.1 emitterCell.scaleSpeed = 0.2 emitterCell.spinRange = (CGFloat)(2.0 * M_PI) self.emitterLayer.emitterCells = [emitterCell]; self.view.layer.insertSublayer(self.emitterLayer, atIndex: 0)
続いて、viewWillAppear()内に以下のソースを記述します。
viewWillAppear()内
let emitterAnimation = CABasicAnimation(keyPath: "emitterCells.star.birthRate") emitterAnimation.fromValue = 150.0 emitterAnimation.toValue = 0.0 emitterAnimation.duration = 5.0 emitterAnimation.timingFunction = CAMediaTimingFunction(name:kCAMediaTimingFunctionLinear) self.emitterLayer.addAnimation(emitterAnimation, forKey: "starAnimation")
それでは実行してみましょう。
たったこれだけのコードで、星がキラキラと色や大きさ、透明度を変えながら放出していく表現ができました!
プロパティの内容さえわかってしまえば、あとは好きなように値を設定するだけで様々なパーティクルを作ることができます。
とっても簡単ですね。
同じように、HeartViewController.swiftを開いて、ハートが画面下からフワフワと浮かんでくるパーティカルを作ります。
viewDidLoad()内
self.emitterLayer = CAEmitterLayer() self.emitterLayer.emitterPosition = CGPointMake(self.view.bounds.size.width / 2.0, self.view.bounds.size.height + 50) self.emitterLayer.emitterSize = CGSizeMake(view.bounds.size.width * 2.0, 0.0) self.emitterLayer.emitterMode = kCAEmitterLayerOutline self.emitterLayer.emitterShape = kCAEmitterLayerLine let emitterCell = CAEmitterCell() emitterCell.birthRate = 1.0 emitterCell.lifetime = 100.0 emitterCell.velocity = -10 emitterCell.velocityRange = 10 emitterCell.yAcceleration = -2 emitterCell.emissionRange = (CGFloat)(0.5 * M_PI) emitterCell.contents = UIImage(named:"heart")!.CGImage emitterCell.color = UIColor(red:1.0, green:0.0, blue:0.5, alpha:0.5).CGColor emitterCell.redRange = 0.5 emitterCell.blueRange = 0.3 emitterCell.spinRange = (CGFloat)(0.25 * M_PI) self.emitterLayer.shadowOpacity = 1.0 self.emitterLayer.shadowRadius = 0.0 self.emitterLayer.shadowOffset = CGSizeMake(0.0, 1.0) self.emitterLayer.shadowColor = UIColor(white: 1.0, alpha: 1.0).CGColor self.emitterLayer.emitterCells = [emitterCell] self.view.layer.insertSublayer(self.emitterLayer, atIndex: 0)
実行してみますと・・・
パーティカルを描画していない時よりも女の子の感情が伝わってくるようになりました。
最後に、FireViewController.swiftを開いて、炎がメラメラと燃え上がるパーティカルを作ります。
viewDidLoad()内
self.emitterLayer = CAEmitterLayer() self.emitterLayer.emitterPosition = CGPointMake(self.view.bounds.size.width / 2.0, self.view.bounds.size.height / 4.0 * 3.0) self.emitterLayer.emitterSize = CGSizeMake(self.view.bounds.size.width / 2.0, 0.0) self.emitterLayer.emitterMode = kCAEmitterLayerOutline self.emitterLayer.emitterShape = kCAEmitterLayerLine self.emitterLayer.renderMode = kCAEmitterLayerAdditive let emitterCell = CAEmitterCell() emitterCell.name = "fire" emitterCell.birthRate = 100 emitterCell.emissionLongitude = (CGFloat)(M_PI) emitterCell.velocity = -50 emitterCell.velocityRange = 20 emitterCell.emissionRange = 1.1 emitterCell.yAcceleration = -50 emitterCell.scaleSpeed = 0.5 emitterCell.lifetime = 50 emitterCell.lifetimeRange = (50.0 * 0.35) emitterCell.contents = UIImage(named:"fire")!.CGImage emitterCell.color = UIColor(red:0.7, green:0.3, blue:0.1, alpha:0.1).CGColor emitterCell.alphaSpeed = -0.1 / (emitterCell.lifetime * 2.0) self.emitterLayer.emitterCells = [emitterCell]; self.view.layer.insertSublayer(self.emitterLayer, atIndex: 0) var fireValue = 0.6 self.emitterLayer.setValue(fireValue * 500, forKey:"emitterCells.fire.birthRate") self.emitterLayer.setValue(fireValue, forKey:"emitterCells.fire.lifetime") self.emitterLayer.setValue(fireValue * 0.35, forKey:"emitterCells.fire.lifetimeRange") self.emitterLayer.emitterSize = CGSizeMake((CGFloat)(50.0 * fireValue), 0)
実行です・・・
女の子はメラメラと勢いよく燃える炎にハッとしているようです。
このように、CAEmitterとCAEmitterCellを利用すると数行のコードを記述するだけで簡単にパーティクルを描画できます。
今回はCAEmitterとCAEmitterCellのご紹介までにしたいと思います。
次回は細かい設定などを説明していきたいなと思います。
パーティクルの利用シーンとしては、ゲームでの演出(爆発や雨、雪、火、煙のエフェクト etc.)や、UIでの演出(アイコンやタイトルからキラキラしたパーティクルを放出させたり、遷移元の画面を煙とともに非表示にしたり etc.)があります。
アプリの背景が、春になると桜が舞っていたり、冬になると雪の結晶が降ってきたりと、そんなアプリを見たことがあったりするかと思います。
意外と簡単に実装できるので、ちょっとアプリを華やかにしたい時に今回ご紹介した方法で演出してみてはいかがでしょうか☆*:.。.