Swift3 + SpriteKit でゲームを開発した話


概要

本記事内では SpriteKit を使って開発した ゲームアプリの経験から感じた Tips やノウハウを紹介しようと思います
チュートリアル的な SpriteKit の使い方は紹介しません
内容は実際に審査も行い公開されたアプリを元にしていますが個人的な見解も含まれるのでご了承ください (公開しているアプリについては後述の「作品紹介」を御覧ください」)

SpriteKit とは

簡単に言えば iOS 上で 2D ゲームを作成するためのフレームワークです
作れるゲームのイメージとしてはブロック崩しやインベーダゲームのような縦方向のシューティングゲームや FlappyBird のような横スクロールゲームが開発できます
基本はシーン (SKScene) 上に敵やキャラクタなどのノード (SKSpriteNode) を配置して開発します
UIKit で使われる Storyboard のように .sks ファイルという UI を管理するファイルを編集することで直感的に UI を作成することができます
もちろんコードだけで UI を開発することも可能です

Xcode で新規にプロジェクトを作成する際に Game プロジェクトとして作成すればすぐに SpriteKit が使えます
Web 上には個人の方が書かれたブログや動画などチュートリアルとなる情報が豊富に用意されているので簡単なゲームであればすぐにできると思います

ただ注意が必要なのが Swift のバージョンや Objective-C で書かれているサンプルなどもあるのでご自身が開発する環境 (Xcode のバージョンや言語の種類) に合わせて参考にするようにしてください
なお本記事内では Xcode9 + Swift3 で開発することを想定しています

なぜ SpriteKit を使うのか

まず自分がゲームを開発したいとなったときにはゲームエンジンやフレームワークを選定すると思います
今の世の中には Unity や Unreal Engine など 3D ゲームを簡単に開発できるゲームエンジンもあります
また、2D ゲームであれば Cocos2d-x などもあります
更に上記のゲームエンジンたちは「マルチプラットフォーム」対応しており 1 つのコードで Android や PS4, VR 対応も可能です

それなのになぜ SpriteKit を採用するのか (したのか) というと個人的には以下の理由に尽きると思います

  • もともと UIKit を使った iOS アプリを開発しており Swift や Xcode の知識があるため導入障壁が低い
  • 無料で使える (Developer Program の登録などは必要ですが)
  • 2D ゲームを作りたい

かなと思います
「Apple 製品が好き」「せっかく Mac を持ってて Xcode で開発しないのもなぁ」など他にもいろいろな理由はあると思いますが多くは上記かなと思います
特に一番上の導入障壁が低いというのが採用の決めてだったかもしれません
他のゲームエンジンを採用した際に C++ や JavaScript など Swift 以外の他の言語を覚える必要は当然出てきます
また IDE もそうで Unity にも専用の IDE がありその操作を覚える必要も出てきます
なので慣れ親しんだ Xcode + Swift をそのまま採用してゲームを作りたいという方には SpriteKit の採用はおすすめできるかなと思います

ただ、前述していますが 3D ゲームは作れません (厳密には他の Kit と組み合わせればそれっぽいのは作れます (後述))
またクロスプラットフォームに対応していないので iOS 専用のゲームになってしまいます (watch, tv には対応できます)
なのでそれらを満たしたいという方にはおすすめしません、素直に Unity などを採用して頑張って勉強したほうが将来的にも良いと思います

ゲームを開発する上でゲームエンジンの選択はかなり肝になるので慎重に選択しましょう
例えば将来的にアプリをマルチプラットフォームに対応させたいと言って SpriteKit -> Unity に乗り換えるとなると不可能ではないですがかなりの開発コストになるので大変なことになると思います
そういった場合は新規で開発するアプリから採用することをおすすめします

開発の王道

個人的にこれがベストかなと思う方法を紹介します
基本の部分だけですが以下の通りです

  • UI は SpriteKit Scene ファイル (.sks) ファイルを使って開発する
  • .sks ファイル内で定義した UI コンポーネント (SKNode) には Swift ファイルから childNode(withName:) を使って参照する
  • 動的に出現させるノードは Swift ファイル内で生成し addChild する
  • 物理エンジンを使いこなす
  • イベント系の関数を使いこなす (タップ、スワイプ、フレーム更新など)

とりあえずこれだけできるようになればそれっぽいゲームはすぐにできるようになると思います
また加えて以下を考慮しながら開発すると良いです

  • SKSpriteNode や SKScene を継承したベースとなるシーン、ノードクラスを作成して新規でシーンやノードを追加する場合はそれらを継承して作成する

これをやっておくことでシーンやノードが多いゲームはコードの冗長化をかなり減らせると思います
理由は単純でゲームを開発すると敵やステージは自ずと増えていきます
それらを追加するたびに毎回 SKScene や SKSpriteNode を継承していると共通処理を毎回記述することになります
なので共通処理をまとめるたベースシーンやベースノードを作成しておくことで冗長化なくせるというわけです
このあたりはオブジェクト指向として当然の実装になるのでリファクタなどを重ねると自ずとこの形になるとは思います

物理エンジンを使いこなす

ゲームを開発する上で物理エンジンはほぼ必須になると思います
SpriteKit にも当然物理エンジンがありノード間の衝突処理や重力、外力を与えることができます
細かい使い方は紹介しませんが主に以下のポイントを抑えておくことをおすすめします

  • ノードに直接設定できる重力や反発係数、摩擦、減衰率の設定の仕方
  • ノード間が衝突したときの判定 (categoryBitMask, collisionBitMask, contactTestBitMask と didBegin)
  • ノードが衝突したときに他のノードの影響を受けるかどうか (isDynamic)

ポイントというか物理エンジンのほぼすべて機能を覚えたほうが良いという感じです
大元は SKPhysicsBody とSKPhysicsContactDelegate という技術になります
これに設定できるパラメータやイベント関数を駆使することで様々なノードの動きを実現し自分の意図したゲームを開発します

例えば「このノードには衝突させたいがこのノードはスルーさせたい」という場合に categoryBitMask, collisionBitMask, contactTestBitMask を適切に設定することで実現することができます
他には「壁に衝突しても減衰せず一定の速さで動き続けるようにしたい」という場合は重量を与えず CGVector で一定の外力を加えかつ反発係数や減衰率は影響しないようにすることで実現できます

こんな感じでノードの動きに合わせて設定するべき項目が理解できるようになっていると開発はスムーズに進むと思います
良くわからないという場合には物理エンジンを採用しないというのも手だと思います (タップやスワイプのイベントだけで遊べるゲームを考えるとか)

他の Kit との組み合わせ

SpriteKit は UIKit をベースに作られています
SKView というビュー上に SKScene と SKNode を配置していますが SKView の大元は UIView になります
なので SKView 上に UIKit の UI コンポーネントを配置することが可能です

例えばボタンですが SpriteKit でボタンを作成しようとすると SKSpriteNode を配置してそのノードに touchDown したらシーンを移動するという処理を実装します
それを UIButton を使うことで画面を切り替えることができるようになります
UIButton を使うことで画面の移動はシーンの切り替えではなく UIView + segue で切り替えできるようになります
つまり Storyboard 上で画面遷移を実装することが可能です
また NavigationController を使えばスワイプバックなどできるようになります

他にも AVFoundation を使って動画の再生や音楽の作成を行うこともできます
SpriteKit にも専用の SKAudioNode があるのでそれを使って音や動画の作成を行うことも可能です

後述しますが最近追加された ARKit と SceneKit と組み合わせることで 3D ゲームを開発することも可能です

こんな感じで SpriteKit は他の Kit と組み合わせることでいろんなことができるようになります
いろんな Kit の一覧はこちらのページで紹介されています

絵を描く技術

これはゲームを開発する上で共通の技術かもしれません
Unity などのゲームエンジンには Asset Store という仕組みがありそこから画像や 3D オブジェクトを取得して使用することができます
SpriteKit には機能としてそういったものは一切ありません
ネット上にフリーの素材はたくさんあるのでそれを使うという手段はありますが著作権など気にする必要が出てきます

最近では無料で使える高機能な編集ソフト (GIMP や Firealpaca など) がたくさんあるので個人的には画像などのリソースも自分で作成できるようになることを薦めます
ペンタプなどあると便利ですがなくてもある程度のものはできるようになると思います
後述で紹介している自分の作品もすべて自分で画像や背景、ロゴなどは作成しています
ただ素人が作るので安っぽく見えてしまうのも事実です
なのでクオリティの高いものにしたいのであれば多少お金を払ったクラウドソーシングなどでロゴの開発などを依頼すると良いかもしれません

ゲームのコンセプトにもよりますが画像などのリソースはゲームを開発するにあたってクオリティを決定する重要な要素になると思っています

作曲する技術

これは上記の絵と感じです
ゲームにおいて音は主に効果音や BGM に使います
これも探さばネット上にフリー素材があると思います
簡単な効果音であればそれでも問題ないですが BGM となるとフリー素材だと被ったりもするので少し使うのが億劫になります

なので音楽も自作できたほうが良いかなとは思います
音楽編集ソフトもフリーでいろいろと出ているのでそれらを使ってソフト音源だけで簡単なものは作れると思います
それでも作曲する技術は多少必要になるので学習コストがかかるのも事実です
自分は絵を描くよりも音を作成するほうが大変だったので公開しているアプリでは効果音のみ自作しています
使用しているのは GarageBand のソフト音源になります

音も画像リソースと同じで自作でプロレベルのものを求めるのであればかなり大変な作業になると思います
更に音の場合はミキサーや音源となる楽器も必要になってくるので尚更大変かと思います

なので音もクラウドソーシングしてしまうというのは全然ありだと思います

審査について

SpriteKit を使ったアプリゲームの審査ですが実は自分は一度もリジェクトされたことがありません
逆に UIKit を使ったユーティリティ系のアプリでは何度もリジェクトされたことがあります
アプリの内容や実装にもよりますがゲーム系のアプリはリジェクトされるのが少ないのかもしれません (完全に個人の経験からの感想です)
非常に簡単でサンプルレベルのものだとリジェクトされるのかもしれません
以下で紹介しているレベルのアプリであれば大丈夫なのかなと

作品紹介

開発期間: 約 1 ヶ月

いわゆる「盛りゲー」です
タップしてぶたを落下させて盛れるだけぶたを盛ります
各ステージにはスコアが設定されており一定のスコア以上でゴールドメダルを獲得することができます
ログインやアイテム交換の概念がありプレイに有利になる要素を追加でゲットすることができます

開発期間: 約 2 週間

タップだけで遊べる 360 度シューティングゲームです
四方八方から攻めてくる敵を手裏剣で倒していきます
使える手裏剣を選択することが可能でステージに合わせて好きな手裏剣を使うことができます
ステージごとに設定されたノルマを達成することでステージクリアとなります

補足資料

UIKit と SpriteKit を比較した資料も書いているので興味あれば御覧ください
https://www.slideshare.net/kakakikikeke/uikit-spritekit

おまけ (SpriteKit + SceneKit + ARKit)

WWDC 2017 のセッションで発表された内容です
Going Beyond 2D with SpriteKit
簡単に言うと SpriteKit を使って 3D ゲームの開発ができるようになります
正確には「3D 空間を使ったゲームが開発できるようになる」と言ったほうが正しいかもしれません

イメージだとペーパーマリオシリーズのような感じのゲームが作れます

SceneKit も ARKit も 3D 空間を提供することができる Kit です
その空間上に 2D の SKSpriteNode などを配置することで 3D ゲームっぽいアプリを作ることができるようになります
紹介している WWDC2017 の動画では簡単な実装方法やデモ動画などがあります

自分も動画を確認しただけで具体的に触ったことがないので自信はありませんが開発方法は SpriteKit などと同じ感じでできそうです
Swift 上でノードを作成し addChild してあとは追加したノードをタップしたときにコールされるイベント関数をハンドリングする感じです
物理エンジンもおそらく使えると思います
たぶん大きく異なるのは座標情報が 2D -> 3D 空間座標になる点かなと思います
次元が 1 つ増えるのでベクトル計算などをする場合は考慮が必要になると思います

ただし条件があり ARKit は iOS11 以上しかサポートされていないのでまだアプリが少ないのが現状かなと思います
SceneKit は iOS8 からサポートしています