2016年3月23日水曜日

SceneKit - 世界はSCNViewでできている

先日リリースしたStandlandでは、SceneKitを使ってみました。
SceneKitを使って実際にアプリをリリースした人はまだあんまりいないだろうなーということで、どんな感じだったかを書いてみようと思います。

SceneKitとは、iOS SDKに含まれている3Dグラフィックのフレームワークです。
モノとしてはUnityと同じアプリケーション層。

球体とかにテクスチャを貼って配置してみたり、光源を置いて影をつけてみたり、空(Skybox)を設定してみたり、重力に合わせて動かしてみたり... と最初に試してみる事としてはUnityと多分変わらないはず。

Metalを使うには iOSの新グラフィックAPI - Metal入門してみる のような処理が必要なのですが、これらを簡単に扱えるようにしたフレームワークです。

では、何でSceneKitを選択してみたか? というと、
  • iOSに特化しているから、汎用的に作られているものよりも処理が早いはず
  • ブラックボックスが少なくコードでいろいろ書ける方が、(私としては)とっつきやすい
  • 直接Metalを扱うほどシビアなものを作ろうとしているわけはない
ということ。

裏の気持ちとしては、
  • どんなものか知りたいという単純な興味
  • SceneKitで使える技が他のアプリ開発にも役立つかもしれない(Unityを学ぶよりは)
  • Appleさんにフィーチャーしてもらいたい
というのも、もちろんあります(笑)。

せっかくなのでSceneKitを使う人のためにあしあとを残してみます。
が、全体は大きすぎるので、今回はSceneKit全体像から。

世界はSCNViewでできている

SceneKitを表示するための大元のViewがSCNViewです。
SCNViewの継承元はUIView
つまり通常のアプリのUIViewの中に一部として入れることもできちゃいます。

基本構成はscnファイルで

SCNViewにあるSCNSceneが、シーンを管理しているクラス。
SCNSceneは、scnファイルを指定してインスタンスします。

scnファイルは、表示するデータが入ったバイナリファイル。
COLLADA形式の3DモデルをXCodeで変換して作成します。
COLLADAがなくても、簡単なものであればXCodeのエディタで作成できます。

実際には一つのscnファイルで全てのモデルを配置するのではなく、各部品で分けて、組み合わせていく形になるかと思うのですが、この部品もscnファイルで作成します。

scnファイルの中に他のscnファイルの参照を置くことができるし、scnの中のノードをプログラムからアクセスして他のSCNSceneに追加もできます。

実際、Standland でも
scnファイルを組み合わせて、世界全体を作成しています。



キャラクタの動きなどのアニメーションについても、scnファイルで切り出しします。
これでアニメーションを切り替えることがプログラムから可能になります。

イベントの取得はUIViewと同じ

UIGestureRecognizerを登録するとちゃんと反応します。

TouchEvent
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?)
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?)
override func touchesCancelled(touches: Set<UITouch>?, withEvent event: UIEvent?)
もちゃんと渡ってきます。

Standlandでは、スワイプ操作でカメラ向きをかえたり、ダブルタップでみんなが一斉にジャンプしていますが、そのイベントの発火元はこれらになっています。

UIViewと同じように扱えるので、すでにアプリ作成を経験している人にとっては良い点ですね。

SceneKit 内のタップ判定



青いちっこいのがGemmy。
この子をタップするとGemゲットできたりジャンプしたりします。
その時必要になるのが、SCNKit上では、なにがタップされたのか?の判定です。

ここで使用するのは、SCNViewの

func hitTest(point: CGPoint, options: [String : AnyObject]?) -> [SCNHitTestResult]

というメソッド。
これでUITapGestureRecognizerで取得できたPointを使用して、SCNKit上でHitしたオブジェクトが取得できます。

HitしたのがGemmyなのか?うさぎなのか?は、ノードの名前で判断します。
そのため、scnファイルの中で設定しているノード名はちゃんとルールを用意しておきましょう。

2DのOverlayはSpriteKit

例えば、ゲーム終了後にスコアを画面上に2Dで表示したい。
という場合、overlayを設定することができます。
overlayは、SKScene .... つまり、SpritKitフレームワークのオブジェクトを利用します。
SCNSceneRenderer#overlaySKScene

...が、Standlandではoverlayは使わず、UIViewをSCNViewの上に置いちゃっています。
理由としては、Storyboard上でレイアウトをしたかったから。
そして、ボタンなどのハイライトとかUIKitの便利な機能を使いたかったから。

AppleTVにも対応する場合、overlayを使いSceneKit/SpriteKitだけで作成した方が楽かもしれません。
あと、SCNViewをインスタンス中にUIViewで表示、アニメーションとかすると、ビシっと線が入ったりして苦しそうになりますのでご注意を。


今日はこれでおしまい。
次回はカメラについて書いてみようと思います!



作成したアプリはこちら↓


Standland - 座りすぎ解消!スタンドランド
• • •