今どき、Unityを使えないゲームプログラマーは仕事の幅が広がらなくなりました。
特にアプリ業界だとUnity案件ばっかりです。私はUnityの経験値はほぼ無いに等しかったのですが、そろそろ本気出そうと、今年に入って「Unity使えるよ」と言えるくらいにレベルを上げました。
実際に私が最初にUnityを覚えたときに実践した方法をまとめました。今までC++でゲームを作っていて、これからUnityを覚えようとしている人には役立つかもしれません。
まえおき
私は生粋のC++プログラマです。
どのくらいかというと、商用ゲームの開発でC++を書き、cocos2d-xみたいなフレームワークを自作できるくらいです。そのフレームワークは今も運用中のスマホゲームで使われてます。そんなこともあってUnityを真剣に触りはじめるのが遅れた!というのは完全に言い訳ですが…;;
C++でプログラミングできる力はどんな環境でも役立つので、決して無駄ではありません。
ゲームプログラマの心得があれば、Unityはすぐに使いこなせるようになります。(たぶん!)
開発環境の歴史
私が最初にUnityを触ってアプリを試作したのは、Unity3の頃でした。
あの頃はPro版じゃないと全機能使えないとか、MonoDevelopが使いにくいとか色々ありました。
でも、いちばんの問題はUnity製のアプリが重くてデカかったことです。
そんなUnity出始めの頃は、各社独自エンジンを作ったり、cocos2d-xを使ったりしてました。
そして私もそこそこネイティブ開発が出来たので、Unityを離れて独自エンジンに走ったわけです。
ゲームエンジンの時代
今はもう完全にゲームエンジンの時代です。
デバイスやプラットフォームの多様化が加速する現代では、Unityのように莫大な資本力と大規模なコミュニティを持つゲームエンジンは強いです。独自エンジンの開発と保守のコストは費用対効果に合わないので、よっぽど体力と技術力のある大きな会社以外は手を出せないでしょうし、やろうとも思わないはずです。もし、安易に独自エンジンで作ろうとしてるチームがあるならば、それはきっとやばいプロジェクトです(苦笑)
cocos2d-xの案件も多少は見かけますが、昔からあるアプリの運用がメインで、新規アプリの開発はほぼUnityになったように思います。3DならUnity!2Dならcocos2d-x!という時代もあったけど、今のUnityは2Dも強くなりました。cocos2d-xが全盛期に比べてメジャーアップデートされなくなりましたし、ツールもころころ変わるので国内では完全に下火の状態です。
これからのアプリ業界のエンジニアにとって、Unityは必須スキルになっていきそうですね。
やってみる
まずは触ってみることが大事です。Unityをダウンロードして満足しているだけではいけません。
取っ掛かりとして、Unityのチュートリアルをやるのも良いのですが、オススメの教書があります。
これをポチらせたい!とかそういうわけじゃなく(笑)、本当にオススメです。
Unity本はいっぱい出てますが、この本はUnityの使い方の入門書としてもわかりやすく、サンプルも実践的なテクニックとして使える内容になっています。例えば、Sceneに配置したGameObjectにDirectorクラスをアタッチして制御するテクニックは、製品レベルでも応用できます。
基礎を学びつつ、応用もできる、まさに教科書と呼べる1冊になっています。
そこまで難しい内容もなくサラッと読めるので、実際に作って試しながら一通りの操作を覚えたら、Unity公式にある2Dシューティングのチュートリアルを進めてみてください。
シューティングは自機の操作、敵の挙動、大量の弾の生成、当たり判定など、ゲーム作りの基本要素を学ぶのに最適なジャンルです。Unityでゲームを作る一通りのお作法も学べます。
このステップを終える頃には、あれ、Unityって簡単じゃん!と思えるようになってるはずです。
おさえておくこと
それは、Unityにどのようなイベントがあり、どんな順番で処理されているか?です。
これはUnityに限った話ではなく、プログラマであれば必ず理解しておく必要があるところです。
最初に気を付けるのはスクリプトライフサイクルフローチャートの初期化の流れです。
これを見ると、AwakeもStartも初期化関数ですが、それぞれ書くべき処理が違います。
AwakeはScene上にインスタンスされたときに呼ばれ、すべてのインスタンスが作成されてUpdateが走る前にStartが呼ばれます。つまり、Awakeの時点では他のインスタンスは作成されていない可能性があるので、参照してはいけません。Awakeは自身のパラメータに対する初期化を書き、Startで制御の初期化を行うようにすると良いです。
public class Sample : MonoBehaviour
{
private float _leftTime;
private Transform _transform;
private void Awake()
{
// Transformコンポーネントをキャッシュする
_transform = transform;
}
private void Start()
{
// 制限時間をセットする
_leftTime = 60.0f;
// ボーナスが発動している場合は+10秒!
// 他のインスタンス(GameManager)を参照して判断する
if (GameManager.Instance.IsTimeBonus)
{
_leftTime += 10.0f;
}
}
}
MonoBehaviourのスクリプトはロード順に処理されるので、実行順序はランダムです。
AwakeとStartを正しく理解して使わないと、起動毎に現象が変わるバグに悩まされる可能性が高くなります。他のイベントの実行順も熟知しておくと適切な設計でコーディングできるでしょう。
C++からC#へ
C++とC#は構文が似ているので、特に混乱することはないはずです。
C#はポインタが無いですが、C++で std::shared_ptr などのスマートポインタを使いこなしていたプログラマならば、インスタンスの寿命を意識したコーディングも容易です。(きっと!)
C++には無く、C#の構文でいちばん扱いに気を付けたいのはプロパティです。
public class Sample
{
public int Count { get; set; }
private int _count;
private void Update()
{
// Countプロパティのsetが呼ばれる
Count = 100;
// Countプロパティのgetが呼ばれる
int count = Count;
// プロパティの中身はメソッドなのでオーバーヘッドがある
for (int i = 0; i < 100; i++)
{
Count++;
}
// 変数はプリミティブに処理されるので速い(プロパティより4倍以上高速)
for (int i = 0; i < 100; i++)
{
_count++;
}
}
}
プロパティは便利ですが、デメリットもあると考えています。
- 単に変数アクセスなのか、内部で処理しているかの見分けが付かない。
- 値をsetしている箇所とgetしている箇所をコード全体から検索することが難しい。
- 変数名からは想像できない実装が暗黙的に処理される可能性がある。
- 変数アクセスにように多用すると、オーバーヘッドがパフォーマンスの低下を招く。
このように単なるシンタックスシュガーとして乱用するとリスクも出てきます。
プロパティには複雑な処理を書かず、用途に応じて変数とメソッドを使い分けると良いでしょう。
1本作り切る
私はUnityを本格的に使い始めて1ヵ月ちょいでミニゲームを作って公開しました。
Unityでゲームを作れるようになることが目的だったので、1本作り切ることにしました。
その方が明確なゴールが定義されますし、実際に遊べるゲームを作りながら学んだ方が楽しいです。
実践でゲームを作ると、チュートリアルと違ってイレギュラーな課題にも直面しやすいです。
C++ならこう作るけど、Unityならどう作るんだろう?と具体的な解決策を調べながらできるので、上達が早くなることが期待できるのでオススメの方法です。
ただし、いきなりビッグタイトルを作ろうとしてはいけません!
1ヵ月くらいの工数で作れるミニゲームで、課題を作って取り組むのがベストです。
可能ならアプリを公開するところまで視野にいれて計画すると、Unityでゲームを完成させてストアに公開するまでの一連のプロセスを学べます。
ここまでやれば、小さな案件を1つこなしたのと同じです。
もしかすると末端の作業をやるだけの仕事よりも得られるものはデカいはずです!
どうせやるならUnityでゲーム作りを楽しみながら習得しちゃいましょう!
Unityの案件が来るのを待つのではなく、自分で実績を作っちゃえばいいんです。
取っ掛かりはこんなところです。また次回の記事でいろいろ役立つ情報をまとめていきます。