読者です 読者をやめる 読者になる 読者になる

【Swift】UIKitベースの画面でSpriteKitでエフェクトを追加する

iOSオールスターズでSpriteKitがUIKit上で使えることを知った

iOSオールスターズというイベントに行ってきた。イベントレポート書こうと思ったけど、最速でいいのがまとまってたのでさぼりましたw

ためになる発表が多かったけど、その中でも @ryusukefuda さんのSpriteKitでリッチな演出を追加するって発表で、UIKit上でも簡単にSpriteKitを取り込めるというのを初めて知ったので試してみた。

目指すもの

Twitterのファボしたときのきらりーんってアニメーション。これっぽいのが作りたい。

f:id:masato47744:20150216022856g:plain

まずはSpriteKitの基本を知る

そもそもどうやってUIKit上にSpriteKitのオブジェクトを追加できるかがわからないのでそれを調べてみた。SpriteKitのビューを貼るだけの最低限の作業を簡単にまとめるとこんな感じ。

  1. SKSceneを作る。
  2. SKViewを作る
  3. SKViewで1をpresentする
  4. SKViewをself.viewにはる

パーティクルをUIKit上にはる

基本がわかったところでパーティクルを表示してみる。

SKSceneをつくる

SKSceneが実際に画面上でユーザーの目に触れる部分。なので、clearColorを指定してる。

// STEP1: 100×100の大きさのものを作る
let w = CGFloat(100), h = CGFloat(100)
let scene = SKScene(size: CGSizeMake(w, h))
scene.backgroundColor = UIColor.clearColor()

SKViewを作ってはる

Viewと名乗っておきながらこいつは画面上では目に見えない。backgroundColorは持ってるんだけど、色を指定しても表示されない。UIKitでいうContainerViewに近いかなー。SKSceneをpresentして、addSubviewしておく。

// STEP2: self.viewの中心付近に貼る
let centerX = CGRectGetMidX(self.view.frame)
let centerY = CGRectGetMidY(self.view.frame)
let skFrame = CGRectMake(centerX - w / 2, centerY - h / 2, w, h)
let skView = SKView(frame: skFrame) // インスタンス変数で宣言してる
skView.allowsTransparency = true // UIKit上で使うときは必須。後ろが黒くなっちゃう
skView.userInteractionEnabled = false // UIKitで使うときは必須。UIKit側でイベントがとれない
skView.presentScene(scene)
        
// STEP3: add sk view
self.view.addSubview(skView)

ここまでで、SpriteKitの表示領域が見えるようになってる。(試しにClearColorじゃなくしたりすればみれる) 次は、パーティクルの表示

きらりーんってなるパーティクルを作る

パーティクルの種類ってテンプレートだと、bokeh、fire、spark、smokeとか色々あって、どれを選べばいいのかーとかよくわからなかったけど全部見てみたらどれももとは同じもので、パラメータだけが違うものだということが分かった。要は、fireとsparkって同じでtextureとしてspark.pngを使っていて、あとはパラメータを変えれば、fireにもsparkにもなるってこと。

パラメータをいじってみる

sparkが一番近そう。で、色々いじってるとX方向の加速度とかY方向の加速度がいじれたりパーティクルが飛び散ったりする方向とかランダム具合とかで設定するんだなーってことが分かった。色々いじってなんか無理やりきらりーんに一番近そうっぽくしてみた。まぁ全然違うんだけどw まぁこれをtwinkle.sksって名前で保存する。

パーティクルをコードからシーンに追加する

さっき作ったsksファイルから SKEmitterNodeを作る。それをsceneaddChildすることで表示される。

// STEP4: add particle to scene
let path = NSBundle.mainBundle().pathForResource(kParticleName, ofType: "sks")
let particle = NSKeyedUnarchiver.unarchiveObjectWithFile(path!) as SKEmitterNode
particle.name = kParticleName
particle.position = CGPointMake(w / 2, h / 2)
scene.addChild(particle)

完成品

星が拡大するアニメーションもつけて、追加したのがこれ。全然似てないw

mpon/TwinkleButton · GitHub

まとめ

ほんとうに簡単だった。まぁ理解するまではちょっと時間かかったけど。大量にオブジェクトをはったときのパフォーマンスとかは考える必要ありそうだけど。 そして、Twitterのきらりーんのアニメーションとはまったく似てないw