SpriteKitで静止したラベルを表示する
まずはじめに、まったくSpriteKitらしいとは思えない利用方法から示しましょう。それは静止したラベル(文字列)を画面に表示することです。なんのためにそんなことをするのかと言えば、その単純なプログラムの中に、SpriteKitの基本的な要素が含まれているからです。そこからスタートして、徐々に要素を追加し、SpriteKitならではのアニメーションを実現してきます。
SpriteKitの最も基本的な要素の1つに「シーン」があります。シーン(scene)は、一般的には「景色」ですが、映画や演劇などでは「場面」のことですね。ゲームでは「面」に相当する概念で、SpriteKitでは、ある意味仮想的な「画面」のことだと考えられます。あるいはその画面を構成する要素の集合のようなものだと思ってください。いずれにしてもSpriteKitでは、SKSceneというクラスでシーンを表しています。ちなみに、SpriteKitに含まれるクラスの名前の多くは、それがSpriteKitに属するものであることを明示するため、「SK」で始まっています。
最初のプログラムでは、シーンの中に「ノード」としてラベルを配置します。
ノード(node)とは、一般には節(ふし)とか交点のことで、ネットワークでは分岐点のような意味で使います。SpriteKitでは、シーンの中に配置する物体のことだと思えばいいでしょう。SKLabelNodeは、文字列からノードを作るクラスです。ここでは、SKSceneクラスのdidMoveメソッドの中で「ASCII倶楽部」という文字列から作成したラベルノードを配置しています。このdidMoveというのは、通常のビューコントローラーのviewDidLoadのようなものだと考えられます。つまりシーンとして最初に実行したいことを、この中に書けばいいのです。
シーンは、そのままでは目に見えません。シーンを表示するために用意されたSKViewという一種のビューに張り付け、さらにそのビュー(SKViewのオブジェクト)をビューコントローラーのビューとして設定する必要があります。
これで、シーンの中にノードとして配置された文字列が、そのシーンを張り付けたビューとして画面に表示されました。なお、ここではシーンの初期の大きさを、縦長の幅384、高さ512ポイントに固定しています。シーンを作成する際には大きさを指定する必要がありますが、それはあとから変更するのが困難なため、最初にiPadの横向き画面の右半分に表示するプレイグラウンドのグラフィック画面を想定し、それにだいたい合う縦横比のサイズにしています。
アクションを組み合わせてノードを動かす
とりあえず、シーンの中にノードを静止画として表示することができました。次に、このシーンの中でノードを動かしてみましょう。ゲームの感覚で言えば、1つの画面の中でキャラクターを動かすような動作です。
動きを表現するためにSpriteKitはSKActionというクラスを用意しています。そこには、既定のアクションとして、移動、回転、スケール変更、フェードイン、フェードアウトなど、いろいろなものが含まれています。それらを簡単に作成できるように、アクションの種類ごとに簡単に作成できるクラスメソッドが用意されています。ここでは、その中から、fadeIn、rotate、scale、fadeOutのメソッドを使ってアクションを作成しました。
アクションは、ノードの持つrunというメソッドを使って、個々のノードに適用することができます。複数のアクションを順番に適用する場合には、SKActionクラスの備えるsequenceメソッドを使って、アクションの配列を与えることができます。この例では配列に入れた、fadeIn、rotate、scale、fadeOutの各アクションが表すアニメーションが順番に実行されることになります。
つまり、プログラムを起動すると2秒かけてフェードインしたあと、1.5秒かけてその場で2回転し、1秒かけて3倍の大きさに拡大し、最後に1秒でフェードアウトするという一連のアニメーションが動きます。
画像から作るノード=スプライトを動かしてみる
文字列から作ったラベルノードに対するアクションだけでは、ゲーム用のアニメーションという感触も、いまひとつかもしれません。そこで、次に画像を読み込み、それをスプライトとして表示して、アクションで動かしてみることにします。これでSpriteKitという名前から受ける印象を裏切らないものになるはずです。
画像からスプライトを作成するには、その名もSKSpriteNodeというクラスを使います。画像ファイル名を指定して初期化するだけで、スプライトノードが作成できます。ここでは、以前にも使った「ASCII倶楽部」のロゴ画像を「clubName.png」という名前でiCloudドライブに保存し、そこからプレイグラウンドに読み込んだものを使いました。
ノードの作成部分だけを変更して動かしてみましょう。文字列がロゴ画像に置き換わった以外は、当然ながら、まったく同じアニメーションが実行されます。
タッチした場所にスプライトを出現させる
ここまでで、最初から決まった位置(画面の真ん中)にスプライトを配置して、アクションを使って動かせるようになりました。次に、画面にタッチした位置にスプライトを出現させる方法を考えてみましょう。
これまではdidMoveメソッドを利用して、シーンが初期化されて画面に表示されるタイミングでスプライトを作成して配置し、そこからアクションをスタートさせていました。シーンでは、touchesBegan、またはtouchesEndedというメソッドの中身を書くことで、ユーザーが画面にタッチしたタイミングで、何らかの処理を実行できるようになっています。これは、SKSceneクラスの親が、SKEffectNodeであり、その親がSKNode、さらにその親がUIResponderというiOSのユーザー操作を扱うためのクラスだから可能になることです。
ここでは、didMoveメソッドではシーンの背景色を設定するだけにして、touchesBeganの中でタッチした場所にスプライトを配置し、一連のアクションを適用するようにしています。
このメソッドの先頭では、Swiftのguardという構文を使って、タッチをエラーなく確実に取得して処理できるようにしています。また、今回は、アクションを少し複雑にしています。複数のアクションをgroupメソッドで組み合わせて同時に動くようにしたものを、さらにシーケンスとして順番に実行するようにしてみました。具体的には、フェードインとスケール、回転と移動、スケールとフェードアウトをそれぞれ組み合わせた3つのグループを作成し、それらをシーケンスとして順番に適用しています。
このプログラムを動かすと、画面には、最初は何もノードが見えないグレーのシーンが表示されます。
ここでシーンのどこかにタッチすると、そこにASCII倶楽部のロゴが、大きさゼロからフェードインしながら拡大して表示され、元の大きさになったところで1回転しながらランダムな位置に移動し、その後10倍まで拡大しながらフェードアウトするというアニメーションが表示されます。
ノードのアクションによるアニメーションの実行中も、タッチ操作を検出できるので、シーンの中には複数のスプライトノードを同時に表示して動かすことも可能です。
次回の予定
今回は、シーンにラベルノードとスプライトノードを配置し、アクションで動かすというSpriteKitの最も基本的な機能を試しました。SpriteKitには、まだまだ多彩な機能が用意されています。次回は、シーンやノードに設定された重力や摩擦、弾力などに応じてノードが自律的に動作する、一種の物理シミュレーション機能を試してみたいと思います。高度な処理が、あまりに簡単に実現できることに、きっと驚かれるでしょう。