#はじめに
僕はもともとObjective-C
の時代からゲームを作っていました。
そして半年前からUnity
でゲームを作るようになりました。
本記事では、この変更の理由とSwift
とUnity
のテクノロジーの違いを書いています。
#僕が使ったテクノロジーについて
ここでは僕が使ってきたテクノロジーとそのテクノロジーを使わなくなった理由を書いていきます。
##OpenGL2
ゲームと言ったら動的に動く物!
という理由で調べたところアニメーションなどに適しているのがOpenGL
だったため、一冊の本を買ってOpenGL
を学びました。
OpenGL
をObjective-C
で制御してシューティングゲームを作りました。
###辞めた理由
OpenGL
は2Dのゲームを描画するための技術なのですが、知識がないとかなり大変です。
例えばPNG
ファイルを取り込んで画面に出すだけでもかなり多くのコードを書く必要があります。
また、制御を誤ると画面がちらついたり1フレーム前に描画した画像が残像のように残ってしまったりします。
例えばドラクエのようにマップ内を歩き回る処理を書く場合は、移動のたびに背景のマップを全描画する必要がありました。(僕のスキルでは)
とにかく難しくコード量も多いため3作品ほど作ったところで他のテクノロジーに変えることにしました。
##Cocos2d-iPhone(SpriteBuilder)
「OpenGLを直接使わずにOpenGLを扱える技術が何かないか?」
と調べたところUnity
とCocos2d
が見つかりました。
この時にUnity
を選択すればよかったのですが、当時のUnity
は3Dに特化していて僕には敷居が高い物でした。
また、Cocos2d-iPhone
は当時の最新言語であるSwift
でコーディングができたため勉強も兼ねてCocos2d-iPhone
を選択しました。
(おかげで当時業務で使っていたSwiftのスキルが上達しました。)
Cocos2d
はOpenGL
を容易に操作できる上にTiled
というタイルマップのライブラリーもサポートしていたため開発速度は一気に向上しました。
(Cocos2d-iPhone
を使う前は自前でTiled
のデータを読み込んでいたので、バグも多くコード量も多かったのです。)
正直この技術最高じゃない!と思ってました。
###辞めた理由
しかし、僕がこのCocos2d-iPhone
に飛びついた瞬間にCocos2d-iPhone
のサポートは終わってしまいました。
サポートが終わってもしばらく使っていたのですが、XCodeがアップデートするたびにCocos2d-iPhone
の中身を書き換えないと動かない状況に陥りました。
(この作業は本当に苦痛でした。サポートされていないため文献もなく、Cocos2d-iPhone
の中身をあてもなく彷徨って変更して確認して・・・という地獄のような作業でした。)
ここで僕は再び露頭に迷ってしまいました。
##SpriteKit
OpenGL
を直接触るのは嫌だし、どうしようかと思っていたところにApple社からSpriteKit
が発表されました。
これを使えばOpenGL
を直接触らずに操作ができる上に、Apple社がサポートしているからサポートが打ち切られる事はないと思い飛びつきました。
Cocos2d-iPhone
の二の舞は嫌だったのでCocos2d-x
を選択する事はありませんでした。
(C++を触るのが嫌だったという理由もあります。)
###辞めた理由
しかし、SpriteKit
はCocos2d
に比べると様々な点で劣ってました。
例えばTiled
のサポートは無い(途中で中途半端にサポートされましたが・・・)ため、マップを作る処理は自前でした。
また、Scene
の作成用のツールを使っているととにかく落ちまくりました。
長い間使っていたのですが、なかなか便利になりませんでした。
どうやらApple社はこのテクノロジーを改善していく気が無いのだと感じたのです。
##Swift
上記の理由からApple
社純正のSwiftでUIよりもゲーム性に特化したゲーム作りに舵を切り始めます。
SpriteKit
はアニメーションが必要なところだけで使おうと割り切りました。
###辞めた理由
純正なのでUI周りの作成は問題がなかったのですが、アニメーションを入れるためにSpriteKit
を入れると座標計算方法が違うためxib
ファイルとsks
ファイルでの操作性を統一させるのが困難でした。
もう少しアニメーションを入れたいと思っても、上記の理由で煩雑なコードになるため実現ができませんでした。
#Unityに変えた理由
このような紆余曲折があってUnity
にたどり着きました。(すごく回り道をした気分です。)
この時代になるとUnity
も2Dゲームの実績が多くなってました。
Unity
を選んだ大きな理由は以下になります。
- 僕が調べた限りでは一番メジャーだった。
- クロスプラットフォームだった。
- 文献が数多く存在していた。
- Unityだけで完結していると思った。(実際はEditerはVBなどの選択をする必要があった)
- C#で書ける。(僕はC#の経験者だった。)
これらの理由からUnity
でゲームを作ってみようと決めました。
##戸惑った点
Unity
を始めた時に一番戸惑ったのがScene
という単位でゲームを作る事でした。
Xcode
でゲームを作る場合はStoryBoard
を使ってスタート画面を設定したり、AppDelegate
からsks
やxib
を呼び出せるので導線がわかりやすかったのですがUnity
にはこのような明確な導線が見当たらなかったので戸惑いました。
「Scene
間でのデータのやりとりはどうすれば良いのか?」なども戸惑いました。
共通部品の作成方法であるPrefab
についても開発者ごとに意見が違ったため、どの方法がベストなのだろうか?と悩みました。
あと、フォルダの名前によって役割が変わるためどのようなフォルダ構成にすれば良いのか悩みました。
(これは今も悩んでます。)
ついでに言うとモダン言語であるSwift
から若干レガシーな言語であるC#
に戻ったので、コードを書く時に不便だなーと思いました。
(もちろん便利な点もありますが、やはり後発言語の方が書きやすいです。C#のオプショナルは貧弱なので、Swiftから移ってくるとコードに違和感があります。ラムダも冗長だし・・・とこの辺りは書き出すと止まらないです。)
##変えて良かった点
書くまでもなくOpenGLやMetalという下位層のレイヤーを触らなくて済むのがUnityの素晴らしい点です。
SpriteKit
も下位層は触らなくても良いのですが、エディターがよく落ちる上に扱えるオブジェクトが少ない(テキストボックスさえ使えない)レベル。なので、これだけでもUnityに置き換えた大きなメリットです。
###UI周り
これが一番の恩恵です。
Unity
はUI
周り処理がとても書きやすいです。
SpriteKit
を使うと途中で落ちてしまうことが多々ありましたが、Unity
ではあまり落ちませんでした。(稀に落ちる)
それに、煩雑なUIを作ることに長けている上に、共通部品であるPrefab
の設計など本当に秀逸でした。
ライティング周りも少し調べれば2DLightなどがあったため雰囲気を出しやすかったです。
とにかくUI周りに関しては、Googleで調べれば大抵の事が実現できたのが良かったです。
###クロスプラットフォーム
他にも各プラットフォームのサポートが手厚いため多少の手間でiOS
とAndroid
の対応ができるのもよかったです。
C#はコード量が若干多いですが、慣れるとあまり気になりませんでした。
###音源周り
これもUnityがサポートしていて、細かい設定周りのサポートが簡単(本を参考にしてますが・・・)に設定できるのが良かったです。
(これ、XCodeで実装すると音が鳴らないタイミングとかがありました。)
###タイルマップ
Cocos2d
に比べると弱いですが、タイルマップ周りの描画がサポートされていたのは助かりました。
(配置したタイルに情報を埋め込みたかったのですが、これはサポートされてませんでした。)
###ローカルデータの扱い
XCodeでローカルデータを扱うと、フォルダの階層がとても深い上にXCodeのバージョンを上げると紛失してしまいます。
しかし、Unity内部でのローカルデータは固定フォルダに出力されるのでUnityのバージョンが変わってもローカルデータがなくならないのは地味に便利でした。
(Unityはバージョン変更が容易にできます。gitで管理しておけば元に戻すのもあまり大変ではありません。)
###FPSタイマーを自作しなくて良い
UnityはFPSタイマーで動くことが前提になっているので、この辺りをの処理を自作で作らなくて良いです。
SpriteKit
の場合はMove
などのメソッドでオブジェクトを動かすのですが、C#
にはコルーチンが用意されているためアニメーション周りでもそこまで困りませんでした。
(FPSとメソッドで移動させるのについて、どちらが良いかは今だにわかりませんがiTweet
みたいなライブラリがあるのを見るとメソッドで動かしたい人がUnityにも居るようです。)
僕はOpneGL時代に自作FPSを作って苦労してたので、コルーチンがあるだけで随分楽にコードがけるようになったなーと思いました。
###ScriptableObjectが使える。
XCodeで設定周りを記述するときはPlist
が主力になります。
このPlist
はある程度のレベルなら良いのですが、データが増えてくると管理が煩雑になります。
その点はUnityのScriptableObject
を使うと(癖はありますが)スキーマーを自在に作れるので管理が楽にできました。
他にもExcelなどを使ってインポートするなどもできるようですが、これはXCodeでも出来るので割愛。
(僕は出来るだけ同一環境でデータを管理したいのでExcelなどでコンバートする二重管理方式があまり好きでは無いのです・・・)
###課金周り
スモール実装なら驚くほど簡単です。
IAPを使えばほとんどコードを書かずに実装できます。
レシートチェックとかを入れると。。。まぁ、それはどの環境でも大変ですよね。
###AssetStoreがある
欲しいプログラムや素材をすぐに購入できる仕組みがあります。
これは本当にありがたいです。
僕はまだUnity
でゲームをリリースしていませんが、このストアでは数万円〜もしくはもっと買い物をしたかもしれません。
それだけ便利です!
###その他
他にもありますが、とりあえず思い出せる点を書き連ねてみました。
個人的には上記に記載しているUI周りとクロスプラットフォーム周りの恩恵が一番大きいと思っています。
##変えてキツかった点
とはいえ、やはりキツかった点もあります。
戸惑った点にも書いていますが・・・
###プログラム周りが弱い
モダン言語は大抵において過去のプログラムの良いところを採用して作られている場合がほとんどです。
なので、15年近く前に作られたC#とは大きな差があります。
RxSwift
などのライブラリはUniRx
などで代用が効くのが良いのですが、、、基本構文はなかなかの面倒臭さがあります。
- Enumにメソッドがつけられない。(拡張は出来るがコードが散らばる)
- EnumのCaseに漏れがあってもコンパイルエラーにならない。(賛否両論があると思いますが、Swiftのこの機能は生産性を高めます。)
- ラムダ式で
$0
などの省略が使えない。(簡単なラムダ式でも冗長になってしまいます。) - オプショナル型が弱い(一応
?
などは使えますが、オプショナル型ではないのでnullチェックが必要。Nulltable型のコードが冗長になる。) - キャストが弱い(
if let = optional
が使えないのはもちろんで、親オブジェクトに暗黙的にキャストしてくれないので一つ一つジェネリクスのコードを書く必要がある。これ、地味に面倒です。) - Switch文で同じcaseが使えない。(
case a,b:
ということが出来ない上にbreak
必須なので、同じような属性の値でもコードを書く必要が出てくる。) - 変数のスコープが少しわかりにくい。(if文の中だけで使う変数をif文を抜けてから再定義する事ができない。これは僕のプログラムの書き方の問題もあるけれど
item
などの変数をスコープ外と内で別の意味で使わせてくれても良いのに・・・) -
flatMap
系がない。(似て非なる物ならあるのですが、、、まぁ、これは言語特性の問題なので仕方なし。僕はflatMap系を多用するのでちょっと困りました。)
と、まぁ、これも書き出すとキリがないのですが・・・
Swift
からUnity
に移った人はラムダ
とオプショナル
、Enum
に関して「え?」と思うかもしれません。
###多画面対応
Unity
って様々なプラットフォームに対応しているのですが、多画面の対応が少し弱い感じがしました。
XCode
ならConstraints
を使ってラベルが横に長くなったり縦に長くなっても
対応に大した問題はありませんでした。
しかし、Unity
ではこれができません。
基本的には画面のどのあたりに配置するのか?と言うところまでしか対応できません。(多分)
ただ、これはSpriteKit
を使った場合に同様の問題にぶち当たるので処理速度を優先した結果なのかもしれないと思っています。
###スクロールが貧弱
Unity
のスクロールは何も考えずに使うと大量のメモリを消費するようにできています。
ついつい500個くらいのアイテムをスクロールに表示すると上部を表示するだけでも500個のデータがレンダリングされてしまいます。
ただ、これもSpriteKit
と比べると・・・SpriteKit
にはスクロールがないですからね・・・(確か
XCodeのスクロールは癖がありますが、高速にレンダリングできるようになっているので安心して使えます。
結論として、僕はこのスクロール問題を解決するために自作しました。
###Firebaseに冷たい
Firebaseだけじゃないかもしれません。サードパーティーはAndroidとiOSで別々に作られている場合があるためAndroidとiOSで設定の仕方が違います。
Androidはそんなに問題ないのですが、iOSは最終的にPods
を使う必要があるのでUnity
ネイティブの人はインストールに難儀する気がします。
あと、地味にAndroidとiOSで処理結果が違う時があります。(アナリティクスのみ。Realtime database
は同じ感じがします。Firestoreはサポートされていません。)
###多言語は自前
Unity
は全世界で使われているので多言語対応もバッチリかと思ってましたが、これは自前でやるしかありません。
それはXCodeでも実は同じ(XCodeに用意されている機構は使いにくいので大体の人は自前で実装すると思います。)。
###イニシャライズに罠がある
RuntimeInitializeOnLoadMethod
を使うとアプリが起動する前に処理ができるのですが・・・
ここで設定ファイルの読み込みとか、別スレッドを発行とか色々やると稀にアプリが落ちる事があります。
これはただの癖の問題ですが、ついつい便利だから初期化処理をすべて詰め込んでしまうと謎のバグ(起動直後に固まる)に遭遇します。
これ、原因に気がつくまで2〜3週間くらいかかりました。
###動かないバージョンがある
これも仕方がないのですが、MacのバージョンがCatalina
になったてからしばらくの間はUnity
から実機転送しても動かない時期がありました。
XCodeの場合は同じApple社が作っているので実機転送後に動かないことはなかったのですが・・・
なので、Unityのバージョンを変える場合は注意が必要です。
また、Unityのバージョンを変えるとXCodeのPods
を更新する必要があったり多言語用ファイルを作り直す必要があったりするので鬼門です。
#最後に
最後に色々問題点を書きましたが、これは僕がUnity
に慣れていない事も原因ですし乗り越えられない問題でもないです。
むしろ開発効率を見ると遥かにUnity
の方が高いです。
ゲームを作りたい人で、上記に書いている事がクリアーできる人ならUnity
を選択する事をお勧めします。
ただし、業務系に関してはSwift
とKotlin
で別に書く事をお勧めします。
OSに関して直接指示が出せないのは少し厳しいのと、業務系のプログラムはそこまで大きくならない(サーバーで処理を吸収できるはず)ので個別に書く事をお勧めします。